Синхронизация документации и кода
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
# Жизненный цикл загрузки и машина состояний
|
||||
|
||||
Как загрузка проходит путь от приёма источника до разложенных файлов:
|
||||
состояния, переходы и то, что их вызывает. Кто владеет переходами и общее
|
||||
устройство — в [architecture.md](architecture.md); детали распознавания —
|
||||
в [recognition.md](recognition.md); действия человека в ревью — в
|
||||
[review-ux.md](review-ux.md).
|
||||
|
||||
## Граф состояний
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> downloading: ingest (источник отдан в qBittorrent)
|
||||
|
||||
downloading --> completed: файлы на месте
|
||||
downloading --> stuck: stalledDL дольше stuck_after
|
||||
downloading --> failed: metaDL дольше magnet_timeout / error
|
||||
|
||||
completed --> recognizing
|
||||
|
||||
recognizing --> linking: авто (матч в базе + валидация)
|
||||
recognizing --> review: нужно подтверждение / ответ LLM не разобран
|
||||
|
||||
review --> linking: Применить
|
||||
review --> recognizing: Уточнить / Распознать заново
|
||||
review --> deferred: Позже
|
||||
review --> cancelled: Отклонить
|
||||
deferred --> review: любое действие (та же поверхность)
|
||||
|
||||
linking --> done
|
||||
linking --> review: коллизия цели
|
||||
linking --> failed: ошибка ФС
|
||||
|
||||
done --> reverted: Undo
|
||||
|
||||
reverted --> recognizing: Привязать заново
|
||||
cancelled --> recognizing: Привязать заново
|
||||
|
||||
stuck --> downloading: Retry
|
||||
failed --> downloading: Retry
|
||||
|
||||
done --> [*]
|
||||
cancelled --> [*]
|
||||
reverted --> [*]
|
||||
|
||||
note right of cancelled
|
||||
«Отклонить» доступно из любого
|
||||
нетерминального состояния
|
||||
end note
|
||||
```
|
||||
|
||||
Условно-терминальные состояния — `done`, `cancelled`, `failed`,
|
||||
`reverted`: задача в них останавливается, но из `failed`/`stuck` есть
|
||||
**Retry**, а из `reverted`/`cancelled` — **Привязать заново**. `stuck`
|
||||
восстановимо ретраем.
|
||||
|
||||
## Состояния и переходы
|
||||
|
||||
- **ingest → downloading** — приняли источник + контекст, отдали в
|
||||
qBittorrent (категория `qbittorrent.category`), записали в БД с ключом
|
||||
идемпотентности. См. [architecture.md](architecture.md) → «Транспорты».
|
||||
- **downloading / completed** — `worker` поллит qBittorrent
|
||||
(`worker.poll_interval`, 5 с). Готовность — только когда файлы на месте
|
||||
(не `moving`/`checking*`), см. «Завершение в qBittorrent» ниже.
|
||||
- **recognizing** — `recognize` строит план и оценку уверенности
|
||||
([recognition.md](recognition.md)). Невалидный/непарсящийся ответ LLM →
|
||||
review (не failed).
|
||||
- **review** — план уходит человеку ([review-ux.md](review-ux.md)); цикл
|
||||
`review ⇄ recognizing` — перераспознавание по подсказке. «Уточнить» —
|
||||
подсказка + перераспознавание; «Распознать заново» — повторный прогон
|
||||
без новой подсказки, по уже накопленному контексту и подсказкам.
|
||||
- **deferred** — «Позже» паркует задачу; принимает те же команды, что и
|
||||
`review`, и возвращается в поверхность ревью по любому действию.
|
||||
- **linking** — `layout` создаёт хардлинки; идемпотентно, батчем. Коллизия
|
||||
цели возвращает в review, ошибка ФС → failed. См.
|
||||
[architecture.md](architecture.md) → «Раскладка файлов».
|
||||
- **done** — при входе неблокирующе дёргаем пересканирование Jellyfin
|
||||
(опц., см. [architecture.md](architecture.md) → «Пересканирование
|
||||
Jellyfin»); доступен **Undo** → `reverted` (убрать созданные ссылки).
|
||||
- **stuck / failed / cancelled** — не качается дольше таймаута; ошибка
|
||||
(ретраибельна); «Отклонить».
|
||||
- **reverted / cancelled → recognizing** — «Привязать заново»: после
|
||||
отката или отклонения можно перезапустить распознавание для той же
|
||||
раздачи. Перепривязка всегда идёт через review с ручным подтверждением
|
||||
(авто-раскладку не делаем) и требует, чтобы раздача всё ещё была в
|
||||
qBittorrent.
|
||||
|
||||
Все переходы и команды идут через `worker` под per-download блокировкой —
|
||||
два транспорта не гонятся за одно состояние. Состояние персистентно в
|
||||
SQLite; `worker` периодически сверяет qBittorrent с БД и **усыновляет**
|
||||
раздачи с нашей категорией (`qbittorrent.category`) **или** тегом
|
||||
(`qbittorrent.tag`), которых ещё нет в БД, заводя для них задачу в
|
||||
состоянии `downloading`. Категория ставится на добавляемые нами раздачи
|
||||
(push, задаёт savepath); тег позволяет подхватить уже существующую
|
||||
раздачу, не трогая её категорию и файлы (pull).
|
||||
|
||||
## Завершение в qBittorrent
|
||||
|
||||
`worker` опрашивает qBittorrent и сопоставляет его состояния с нашими:
|
||||
|
||||
- **готово к раскладке:** `uploading`/`stalledUP`/`pausedUP`/`stoppedUP`/
|
||||
`queuedUP`/`forcedUP` (имена `paused*`/`stopped*` различаются между qBit
|
||||
v4 и v5 — поддержаны оба).
|
||||
- **переходное, ждём:** `moving`/`checkingUP`/`checkingResumeData`/
|
||||
`allocating` — остаёмся в `downloading`, пока qBit не закончит перенос/
|
||||
проверку (готовность не объявляем, даже если флаги «UP»).
|
||||
- **ещё качается:** `downloading`/`stalledDL`/`metaDL`/`forcedMetaDL`/
|
||||
`queuedDL`/`checkingDL`/`forcedDL`/`pausedDL`/`stoppedDL`.
|
||||
- **застряло/ошибка по таймауту:** `metaDL`/`forcedMetaDL` дольше
|
||||
`magnet_timeout` → `failed`; `stalledDL` дольше `stuck_after` → `stuck`
|
||||
(восстановимо ретраем). Возраст считаем от создания задачи.
|
||||
- **ошибка:** `error`/`missingFiles` → `failed`.
|
||||
|
||||
Пути файлов берём из API (`save_path` + относительные имена из
|
||||
`/torrents/files`, уже включающие корневую папку торрента), не из
|
||||
константы (обычно это уже хост-путь). «Incomplete»-каталог в
|
||||
qBittorrent **включён** (`/srv/media/incomplete`): пока качается — файлы
|
||||
там, по завершении qBit переносит их в `/srv/media/downloads` (состояние
|
||||
`moving` — дожидаемся окончания переноса и только потом берём финальный
|
||||
путь). Подробнее о путях и песочнице — [architecture.md](architecture.md)
|
||||
→ «Пути и контейнеры».
|
||||
Reference in New Issue
Block a user