[medium] fetch_status: завершённый/paused job с непустым target-статусом проваливается в неверный ответ 'not_in_nspd' #1356

Closed
opened 2026-06-14 18:09:03 +00:00 by bot-backend · 1 comment
Collaborator

Описание

Пользователю показывается «кадастр не загружен / не найден» (404-подобное), хотя fetch фактически идёт или поставлен на паузу. Конкретный сценарий: job переходит в 'paused' (_finish_job(..., "paused") — nspd_geo.py:480,520 при WAF consecutive=8 или Celery soft_time_limit=6h), нетронутые targets остаются status='pending'.

Корень

find_active_on_demand_job (строки 106-121) фильтрует j.status IN ('queued','running') — 'paused' не попадает, active-check в fetch_status пропускается. find_recent_completed_job (строки 132-154) НЕ фильтрует job/target по статусу — берёт последний job по created_at DESC независимо от статуса, возвращает paused job с target_status='pending'. В fetch_status обрабатываются только target_status == 'done' и 'failed' — ни один if/elif не срабатывает → выполнение падает в финальный fallback 'not_in_nspd'. Тот же недостаток в find_or_enqueue_fetch (строки 251-264): любой не-'done'/'failed' target_status молча проходит к enqueue нового job вместо ожидания resume.

Evidence

cadastre_fetch.py:324-355:

recent = find_recent_completed_job(db, cad_num)
if recent:
    if recent["target_status"] == "done": ... return not_in_nspd
    elif recent["target_status"] == "failed": ... return failed
# No job at all — first request without prior history
return { "status": "not_in_nspd", "job_id": None, ... }

target_status='pending' при job_status='paused' — задокументированное нормальное состояние (nspd_geo.py:467: «НЕ помечаем failed — остаётся pending»).

Suggested fix

Добавить явную ветку для прочих target_status (pending/None) → вернуть status='fetching' с recent['job_id'] и eta_seconds, а не проваливаться в 'not_in_nspd'. Либо в find_recent_completed_job добавить фильтр на терминальные статусы, чтобы не-терминальные не маскировались под «нет истории». Аналогично исправить find_or_enqueue_fetch.

Обоснование severity (medium)

Неверный ответ пользователю (кадастр «не найден», хотя job на паузе и возобновится), но не потеря данных. Путь достижим при реальной нагрузке (WAF, long-running jobs). Confidence 0.88.


week ревью 1 · multi-agent аудит 2026-06-14 · severity=medium · category=logic

Затронутые файлы:

  • /Users/anton/Птица/gendesign/backend/app/services/site_finder/cadastre_fetch.py
## Описание Пользователю показывается «кадастр не загружен / не найден» (404-подобное), хотя fetch фактически идёт или поставлен на паузу. Конкретный сценарий: job переходит в `'paused'` (`_finish_job(..., "paused")` — nspd_geo.py:480,520 при WAF consecutive=8 или Celery soft_time_limit=6h), нетронутые targets остаются `status='pending'`. ## Корень `find_active_on_demand_job` (строки 106-121) фильтрует `j.status IN ('queued','running')` — 'paused' не попадает, active-check в `fetch_status` пропускается. `find_recent_completed_job` (строки 132-154) НЕ фильтрует job/target по статусу — берёт последний job по `created_at DESC` независимо от статуса, возвращает paused job с `target_status='pending'`. В `fetch_status` обрабатываются только `target_status == 'done'` и `'failed'` — ни один if/elif не срабатывает → выполнение падает в финальный fallback `'not_in_nspd'`. Тот же недостаток в `find_or_enqueue_fetch` (строки 251-264): любой не-'done'/'failed' target_status молча проходит к enqueue нового job вместо ожидания resume. ## Evidence `cadastre_fetch.py:324-355`: ```python recent = find_recent_completed_job(db, cad_num) if recent: if recent["target_status"] == "done": ... return not_in_nspd elif recent["target_status"] == "failed": ... return failed # No job at all — first request without prior history return { "status": "not_in_nspd", "job_id": None, ... } ``` `target_status='pending'` при `job_status='paused'` — задокументированное нормальное состояние (nspd_geo.py:467: «НЕ помечаем failed — остаётся pending»). ## Suggested fix Добавить явную ветку для прочих target_status (pending/None) → вернуть `status='fetching'` с `recent['job_id']` и `eta_seconds`, а не проваливаться в 'not_in_nspd'. Либо в `find_recent_completed_job` добавить фильтр на терминальные статусы, чтобы не-терминальные не маскировались под «нет истории». Аналогично исправить `find_or_enqueue_fetch`. ## Обоснование severity (medium) Неверный ответ пользователю (кадастр «не найден», хотя job на паузе и возобновится), но не потеря данных. Путь достижим при реальной нагрузке (WAF, long-running jobs). Confidence 0.88. --- _week ревью 1 · multi-agent аудит 2026-06-14 · severity=**medium** · category=`logic`_ Затронутые файлы: - `/Users/anton/Птица/gendesign/backend/app/services/site_finder/cadastre_fetch.py`
bot-backend added the
week ревью 1
label 2026-06-14 18:09:03 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:01:51 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: cadastre_fetch.py:106-121 find_active_on_demand_job фильтрует j.status IN ('queued','running') — 'paused' не попадает. cadastre_fetch.py:124-154 find_recent_completed_jobORDER BY j.created_at DESC LIMIT 1 без фильтра по статусу job/target → берёт paused-job с target_status='pending'. fetch_status (:284-355) обрабатывает только target_status == 'done' (:326) и 'failed' (:337) → pending проваливается в финальный fallback 'not_in_nspd' (:347-355). Тот же дефект в find_or_enqueue_fetch:252-264 — pending проходит к enqueue нового job (:266+) вместо ожидания resume.

Paused-состояние с pending-targets реально: backend/app/workers/tasks/nspd_geo.py:477-492 ставит _finish_job(..., "paused") при consecutive_waf >= 8, targets остаются 'pending' (:466 «НЕ помечаем failed — остаётся pending»); soft_time_limit=3600*6 (:355). NB: путь в теле issue (scrapers/nspd_geo.py:480,520) устарел — файл живёт в workers/tasks/nspd_geo.py, строки сместились, логика та же.

Корень: Нет ветки для не-терминальных target_status (pending/None) при job_status='paused'/'queued'-not-seen — ни active-check, ни recent-check их не распознают как «ещё в работе», поэтому пользователь получает 404-подобный not_in_nspd на паузнутом job.

Что править:

  • В fetch_status добавить явную ветку: recent['target_status'] не в ('done','failed') (вкл. pending/None) при job_status='paused'/'queued'/'running' → вернуть status='fetching' с recent['job_id'] + eta_seconds.
  • Либо в find_recent_completed_job фильтровать по терминальным статусам (или вернуть и job_status, чтобы caller различал paused).
  • Симметрично поправить find_or_enqueue_fetch:252-264, чтобы paused-with-pending не приводил к лишнему enqueue.

Что посмотреть:

  • Код: cadastre_fetch.py (find_active_on_demand_job:98, find_recent_completed_job:124, fetch_status:284, find_or_enqueue_fetch:194), workers/tasks/nspd_geo.py (_finish_job:119, paused-ветка :477-492). Добавить тест: paused job + target pending → ожидать 'fetching', не 'not_in_nspd'.
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `cadastre_fetch.py:106-121` `find_active_on_demand_job` фильтрует `j.status IN ('queued','running')` — 'paused' не попадает. `cadastre_fetch.py:124-154` `find_recent_completed_job` — `ORDER BY j.created_at DESC LIMIT 1` без фильтра по статусу job/target → берёт paused-job с `target_status='pending'`. `fetch_status` (`:284-355`) обрабатывает только `target_status == 'done'` (`:326`) и `'failed'` (`:337`) → pending проваливается в финальный fallback `'not_in_nspd'` (`:347-355`). Тот же дефект в `find_or_enqueue_fetch:252-264` — pending проходит к enqueue нового job (`:266+`) вместо ожидания resume. Paused-состояние с pending-targets реально: `backend/app/workers/tasks/nspd_geo.py:477-492` ставит `_finish_job(..., "paused")` при `consecutive_waf >= 8`, targets остаются 'pending' (`:466` «НЕ помечаем failed — остаётся pending»); `soft_time_limit=3600*6` (`:355`). NB: путь в теле issue (`scrapers/nspd_geo.py:480,520`) устарел — файл живёт в `workers/tasks/nspd_geo.py`, строки сместились, логика та же. **Корень:** Нет ветки для не-терминальных `target_status` (pending/None) при job_status='paused'/'queued'-not-seen — ни active-check, ни recent-check их не распознают как «ещё в работе», поэтому пользователь получает 404-подобный `not_in_nspd` на паузнутом job. **Что править:** - В `fetch_status` добавить явную ветку: `recent['target_status']` не в ('done','failed') (вкл. pending/None) при job_status='paused'/'queued'/'running' → вернуть `status='fetching'` с `recent['job_id']` + `eta_seconds`. - Либо в `find_recent_completed_job` фильтровать по терминальным статусам (или вернуть и job_status, чтобы caller различал paused). - Симметрично поправить `find_or_enqueue_fetch:252-264`, чтобы paused-with-pending не приводил к лишнему enqueue. **Что посмотреть:** - Код: `cadastre_fetch.py` (`find_active_on_demand_job:98`, `find_recent_completed_job:124`, `fetch_status:284`, `find_or_enqueue_fetch:194`), `workers/tasks/nspd_geo.py` (`_finish_job:119`, paused-ветка `:477-492`). Добавить тест: paused job + target pending → ожидать 'fetching', не 'not_in_nspd'. - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1356
No description provided.