Раздача активной (downloading) загрузки, исчезнувшая из qBittorrent (удалил пользователь/другой клиент), делала задачу вечным зомби: поллинг промахивался по torrentFor, писал Warn и continue каждый тик — состояние не менялось, уведомления и телеметрии не было, checkTimeouts без торрента не срабатывал. Пропажей источника у downloading не владел никто (сверка рассинхрона покрывает только done/target_missing/orphaned, восстановление — failed/stuck). Активный цикл Poll теперь применяет тот же дебаунс пропажи источника, что и сверка рассинхрона (source_miss_count / source_missing_threshold): после порога подряд идущих промахов задача уходит downloading → failed с distinct error_code source_gone и уведомлением. До порога транзиентная недоступность qBit (рестарт демона) задачу не роняет. source_gone восстановлению сверкой не подлежит (удаление намеренно), но штатно retriable — Retry заново отдаёт сохранённый источник; Retry сбрасывает source_miss_count, чтобы вернувшаяся задача получила полное грейс-окно, а не упала снова на ближайшем тике. Ребро downloading → failed уже было в графе, миграций/полей БД нет. Спека download-tracking дополнена требованием, диаграмма workflow.md — ребром. Change downloading-source-gone заархивирован. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
2.4 KiB
Markdown
39 lines
2.4 KiB
Markdown
# Tasks — Пропажа источника у активной загрузки
|
||
|
||
## 1. Код воркера
|
||
|
||
- [x] 1.1 Ввести `errCodeSourceGone = "source_gone"` в блок кодов ошибок
|
||
(`internal/worker/worker.go`) с комментарием: distinct-код, восстановлению
|
||
сверкой не подлежит, retriable вручную.
|
||
- [x] 1.2 Перестроить активный цикл в `Poll`: при промахе `torrentFor` прогонять
|
||
`debounceSource`; при исчерпании порога — `transition downloading → failed`
|
||
(`source_gone`); до порога — `continue`; при наличии источника — сброс счётчика
|
||
и обычная сверка (`captureInfohashes`/`captureSourceAddedAt`/`reconcile`).
|
||
- [x] 1.3 Убедиться, что `debounceSource` вызывается и при наличии источника
|
||
(сброс накопленных промахов).
|
||
- [x] 1.4 `Retry` сбрасывает `source_miss_count` в 0 (рядом с `SetRetriedAt`),
|
||
чтобы retried `source_gone`-задача получила полное грейс-окно, а не падала
|
||
сразу (см. design «Сброс source_miss_count при Retry»).
|
||
|
||
## 2. Тесты
|
||
|
||
- [x] 2.1 Промах < порога → задача остаётся `downloading`.
|
||
- [x] 2.2 Промах ≥ порога → `downloading → failed`/`source_gone` + `EventFailed`.
|
||
- [x] 2.3 Возврат раздачи до порога → счётчик сброшен, задача ведётся обычной
|
||
сверкой.
|
||
- [x] 2.4 `source_gone` не воскрешается `reconcileRecovery` (источник вернулся —
|
||
задача остаётся `failed`).
|
||
- [x] 2.5 `Retry` задачи `source_gone` сбрасывает `source_miss_count`: после
|
||
retry с ещё-не-видимой раздачей задача остаётся `downloading` полный порог
|
||
тиков (грейс-окно не съедено).
|
||
|
||
## 3. Документация
|
||
|
||
- [x] 3.1 `docs/specs/workflow.md`: добавить ребро `downloading → failed`
|
||
(`source_gone`, пропажа источника) в диаграмму и список переходов.
|
||
|
||
## 4. Верификация
|
||
|
||
- [x] 4.1 `task test` / `task lint` зелёные.
|
||
- [x] 4.2 `openspec validate downloading-source-gone --strict`.
|