ПТИЦА: убрать мёртвую фазу bulk_harvest, которая на каждый квартал запрашивала ПЗЗ у НСПД и писала их в таблицу без читателей #3579
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3579
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/ptica-bulk-harvest-phase25-removal"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
#2985 — фаза 2.5 bulk_harvest: запрос ПЗЗ в НСПД на каждый квартал без читателя
Что было. После основного обхода
harvest_quarterотдельно обходил сеткой слой 875838:client.get_territorial_zones_in_bbox, 7×7 = 49 запросов к НСПД на квартал. Результат писался вcad_territorial_zonesчерез_save_territorial_zones.Почему убираем.
git grep cad_territorial_zonesвне миграций находит только сам писатель. На проде (Poincare, 17.09) от таблицы не зависит ни одно представление или функция:pg_depend/pg_rewriteдают 0,pg_proc.prosrcтоже 0.cad_territorial_zones1 строка (fetched_at 2026-05-24),zone_codeиzone_nameв ней пустые. Два полных прохода по ЕКБ (24.05 и 19.06, по 2408 кварталов) оставили в таблице эту одну строку.nspd_sync→nspd_quarter_dumps.features_json→quarter_dump_lookup._get_zoning.Откуда решение. Решение удалить фазу, а таблицу и данные оставить пришло в постановке задачи 17.09. В #2985 оно не записано: комментариев владельца там нет, есть один комментарий bot-backend от 28.08. В прошлой версии тела PR решение было названо «вариантом (а)», и это неверно. В issue варианты идут без букв: первый — «довести трубу до конца», второй — «убрать Phase 2.5 целиком вместе с таблицей». Этот PR не совпадает ни с одним из них полностью: фаза убрана, таблица осталась. Поэтому здесь стоит
Refs, а не ключевое слово закрытия. Порядок закрытия описан в конце.Что сделано:
harvest_quarter, писатель_save_territorial_zonesи ставший лишнимimport hashlib;NSPDBulkClient.get_territorial_zones_in_bbox. Её вызывала только эта фаза, других вызовов поgit grepнет ни в репозитории, ни вtradein-mvp;tests/services/cadastre/test_bulk_harvest_territorial.pyи мокget_territorial_zones_in_bboxвtest_cadastre_bulk.py;bulk_harvest.pyиbeat_schedule.pyубраны ссылки на фазу. Вbeat_scheduleбыло написано, что ПЗЗ приходят через Phase 2.5, а на деле их приноситnspd_sync;test_cadastre_bulk.py. Там было «grid-walk + territorial_zones фазы пропускаются», теперь «grid-walk фаза пропускается».Чего НЕ трогали. Таблица
cad_territorial_zonesи её данные остались как есть, миграций нет. Файлы102_…sqlи159_…sql— это история, их не меняли.Попутно замечено, в этом PR не трогали. Асинхронный
NSPDBulkClient.get_features_in_bbox_grid(nspd_bulk_client.py:459) остался без вызовов, и ссылка на него вbulk_harvest.py:398теперь ведёт на неиспользуемый код.ird_harvestиopportunity_harvestвызывают одноимённый синхронный методNSPDClient. Это вопрос для отдельного issue.Правки по ревью
Исправлено
(блокирующее) Пункт 2 приёмки не отличал старую версию от новой. Проверил обе улики ревью, обе верны:
phase_stateсливается через shallow||(scrape_cadastre.py:82-84), и терминальный{"phase": "done", …}перетирает ключphase. На проде 17.09 вcadastre_jobs23 задачи (done 12, cancelled 11). Все отработали со старым кодом, где фаза 2.5 была, аphase_state::text LIKE '%territorial_zones%'даёт 0 из 23;cad_territorial_zones1 строка сmin = max(fetched_at) = 2026-05-24 15:16. Проход 19.06 не добавил строк и не обновил эту, хотяON CONFLICT DO UPDATEставитfetched_at = NOW().Пункт 2 переписан на признак из логов воркера (ниже). Одно уточнение к формулировке ревью: строку
harvest_quarter doneбез хвоста пишет иnspd_sync(nspd_sync.py:340,harvest_quarter done: cad=…). Он стоит в beat (nspd-harvest-stale-quarters, пн 04:00 МСК) и выполняется в том жеgendesign-worker-1. Кроме того, синхронныйNSPDClient, которым пользуетсяnspd_sync, пишетget_features_in_bbox_grid layer=875838без двоеточия. Поэтому в приёмке шаблоны заданы точно:harvest_quarter done: quarter=иget_features_in_bbox_grid: layer=875838с двоеточием.Ключевое слово закрытия для #2985 снято, вместо него
Refs. Оба условия ревью пока не выполнены: решения в issue нет, а пункт 2 приёмки на проде ещё не проверен.(неблокирующее) Устаревшие комментарии в тестах, строки 492, 557, 762, 837, 907, 1226. Поправлены отдельным коммитом
8def3402. Приbbox=Noneдействительно пропускается только grid-walk (bulk_harvest.py:176,:335). Поведение тестов не меняется, поэтому тест на эту правку не нужен.(неблокирующее) Ссылка на решение. Раздел «Откуда решение» выше: источник назван, «вариант (а)» убран.
Опровергнутого нет. Мёртвый асинхронный
get_features_in_bbox_gridпризнан, но оставлен на отдельный issue, как и предлагало ревью.Как проверил, что новый признак различает версии. Прогнал
harvest_quarterна настоящемNSPDBulkClient, подменив толькоsearch_by_quarterиwms_feature_info:quarter_bbox_3857возвращает валидный bbox, логи собирались на уровне INFO. Зонд был временным, в PR его нет, после прогона он удалён. Строки по трём шаблонам:старый код (
bulk_harvest.pyиnspd_bulk_client.pyиз85d455e3, main до PR):новый код:
Остальные ветки старого кода тоже проверил по исходнику. Сбой всего слоя или любое другое исключение фазы дают WARNING
harvest_quarter: territorial_zones failed quarter=…, то есть шаблон совпадает. При WAF-бане исключение пробрасывается, и квартал не доходит доharvest_quarter done: quarter=. Значит, в старой версии каждый квартал с валидным bbox, у которого есть строкаdone: quarter=, оставляет и строкуharvest_quarter: territorial_zones. На проде app-логи уровня INFO попадают вdocker logs gendesign-worker-1: воркер запущен с--loglevel=info, и строкиworker_process_init: …изcelery_appвидны в логе.Тест по значению
test_harvest_quarter_makes_no_territorial_zones_request_2985берёт квартал без overflow, с валидным bbox и пустыми meta и проверяет две вещи:["search_by_quarter"];["snapshot_started", "snapshot_done", "done"].Фальсификация (перепрогон после merge origin/main, HEAD
89b4a675)Подставил в worktree
bulk_harvest.pyиnspd_bulk_client.pyиз85d455e3(main до PR, фаза 2.5 на месте). Тест покраснел, pytest rc=1:Затем вернул исправленные файлы.
diff -qс HEAD пустой,git statusчистый, тест снова зелёный (rc=0). Ревьюер отдельно проверил мутацию M2: прямойawait client.get_features_in_bbox_grid(875838, bbox)без обёртки тоже роняет тест (Left contains one more item: 'get_features_in_bbox_grid'). Значит, тест ловит любой лишний вызов НСПД, а не только имя обёртки.Прогоны (backend ПТИЦЫ, rc снят у самого pytest, после merge origin/main
be140328)uv run python -m pytest tests/services/test_cadastre_bulk.py tests/services/cadastre tests/scrapers -q→ 203 passed, 5 skipped, rc=0uv run python -m pytest tests/ -q -p no:cacheprovider→ 5050 passed, 4 failed, 87 skipped, 11 deselected, rc=1. Все 4 падения — известныеtests/ops/test_2203_backup_trailer_grep_dashdash.pyна macOS (BSD mktemp), с правкой не связаныuv run ruff check app tests→ All checks passed, rc=0;ruff format --checkпо 4 изменённым файлам → already formatted, rc=0Ветка уже была запушена, поэтому вместо rebase сделан
merge origin/main. Из main пришли только файлыtradein-mvp/**, конфликтов не было.Деплой
Меняется только
backend/**, поэтому деплой идёт черезdeploy.yml: пересоберутся образы backend, worker и beat. backend и beat пересоздаются всегда, worker — по гарду #3029. Миграций нет. На 17.09 10:25 UTCstatus='running'вkn_scrape_runsиobjective_scrape_runs— 0, вcadastre_jobsнет running/pending, последняя задача 19.06. Непосредственно перед мержем ещё раз проверитьstatus='running'вkn_scrape_runsиobjective_scrape_runs: worker может быть пересоздан.Приёмка на проде
Маркер кода в контейнерах (проверить до 2026-09-20). Сейчас (17.09 10:25 UTC)
docker exec <c> grep -c "_save_territorial_zones\|get_territorial_zones_in_bbox" /app/app/services/cadastre/bulk_harvest.pyдаёт 6 и вgendesign-backend-1, и вgendesign-worker-1. После деплоя в обоих должно быть 0. В старой версии маркер есть, в новой нет, поэтому проверка различает версии.Поведение: в первом ручном bulk harvest после деплоя нет запросов ПЗЗ. Bulk harvest запускается только вручную (
enqueue_cadastre_harvest, очередьgeo), последний раз 19.06. Для этого прогона:docker inspect -f '{{.State.StartedAt}}' gendesign-worker-1раньшеcadastre_jobs.started_atзадачи. Если воркер пересоздали во время прогона, логи неполные и проверка недействительна;docker logs gendesign-worker-1 --since <started_at задачи> 2>&1 | grep -c "harvest_quarter done: quarter="→ больше 0 (прогон дошёл до кварталов);docker logs gendesign-worker-1 --since <started_at задачи> 2>&1 | grep -c "harvest_quarter: territorial_zones"→ 0;docker logs gendesign-worker-1 --since <started_at задачи> 2>&1 | grep -c "get_features_in_bbox_grid: layer=875838"(с двоеточием) → 0.В старой версии на каждый квартал с валидным bbox, у которого есть
done: quarter=, приходится строкаharvest_quarter: territorial_zones(см. «Как проверил» выше). Поэтому ноль при ненулевомdone: quarter=отличает новую версию от старой. Проверка поphase_stateи по числу строк вcad_territorial_zonesне годится: оба признака одинаковы в обеих версиях (см. «Правки по ревью», п. 1).Если до 2026-10-01 ручного прогона не будет, приёмка ограничивается пунктом 1, и это нужно явно записать в #2985 с датой.
Закрытие #2985: вручную, не этим PR. Закрывать после двух шагов: (1) владелец записывает в #2985 решение дословно («решение от 17.09 — удалить фазу 2.5, таблицу и данные оставить»); (2) пройден пункт 2 приёмки или записан отказ от него по сроку 2026-10-01.
Refs #2985
🤖 Generated with Claude Code