feat(sf): ИРД-harvest Celery task → ird_overlays (#1067 B5) #1090

Merged
bot-reviewer merged 1 commit from feat/ird-harvest-worker into main 2026-06-06 18:52:04 +00:00
Owner

Что

backend/app/workers/tasks/ird_harvest.py — периодический harvest готовых НСПД ИРД-слоёв по кварталам ЕКБ → upsert в ird_overlays (м.132, PR #1078). Keystone overlay-движка; analyze читает overlap через ST_Intersects.

Как

  • Слои (ID из nspd_client.LAYERS): ЗОУИТ 37577-37581, ПЗЗ-границы 875838, ОКН 875840, ООПТ 875845, лесничества 875866, береговые 875832/875835. layer_kind = ключ LAYERS.
  • Кварталы ЕКБ: DISTINCT quarter_cad_number из cad_parcels (66:41:%); либо явный список (arg).
  • Per-квартал: search_by_cad(thematic_id=2) → bbox → get_features_in_bbox_grid по каждому слою → upsert по (source_layer_id, geom_data_id).
  • Геометрия НСПД (GeoJSON 3857) → ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(...),3857),4326).
  • content_* НЕ трогаем на ON CONFLICT (тип/ВРИ/регламент пишет резолвер D9 — re-harvest их не затирает).
  • SAVEPOINT per-feature (begin_nested) — битая фича не валит батч; сбой квартала/слоя изолирован; commit один раз.

Регистрация

celery_app.include += ird_harvest. Beat ird-harvest-weekly (Mon 05:00 МСК — до supply-layers 06:00, не конкурирует со scrape_kn 04:15).

Тесты

3 passed: grid-walk loop (1 квартал × N слоёв → upsert), skip пустого квартала, skip фич без geom/geom_data_id. ruff + ruff-format clean.

Refs #1067 (B5). Next: B6 (сид кварталов + VPS smoke прогон), D9 (parcel overlap → analyze), C8 (content-резолв через геопортал).

## Что `backend/app/workers/tasks/ird_harvest.py` — периодический harvest готовых НСПД ИРД-слоёв по кварталам ЕКБ → upsert в `ird_overlays` (м.132, PR #1078). Keystone overlay-движка; analyze читает overlap через `ST_Intersects`. ## Как - Слои (ID из `nspd_client.LAYERS`): ЗОУИТ `37577-37581`, ПЗЗ-границы `875838`, ОКН `875840`, ООПТ `875845`, лесничества `875866`, береговые `875832/875835`. `layer_kind` = ключ LAYERS. - Кварталы ЕКБ: `DISTINCT quarter_cad_number` из `cad_parcels` (`66:41:%`); либо явный список (arg). - Per-квартал: `search_by_cad(thematic_id=2)` → bbox → `get_features_in_bbox_grid` по каждому слою → upsert по `(source_layer_id, geom_data_id)`. - Геометрия НСПД (GeoJSON 3857) → `ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(...),3857),4326)`. - **content_\* НЕ трогаем** на ON CONFLICT (тип/ВРИ/регламент пишет резолвер D9 — re-harvest их не затирает). - SAVEPOINT per-feature (`begin_nested`) — битая фича не валит батч; сбой квартала/слоя изолирован; commit один раз. ## Регистрация `celery_app.include` += `ird_harvest`. Beat `ird-harvest-weekly` (Mon 05:00 МСК — до supply-layers 06:00, не конкурирует со scrape_kn 04:15). ## Тесты 3 passed: grid-walk loop (1 квартал × N слоёв → upsert), skip пустого квартала, skip фич без geom/geom_data_id. ruff + ruff-format clean. Refs #1067 (B5). Next: B6 (сид кварталов + VPS smoke прогон), D9 (parcel overlap → analyze), C8 (content-резолв через геопортал).
lekss361 added 1 commit 2026-06-06 18:46:00 +00:00
feat(sf): ИРД-harvest Celery task → ird_overlays (#1067 B5)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / changes (push) Successful in 7s
CI / backend-tests (push) Successful in 5m51s
CI / backend-tests (pull_request) Successful in 5m45s
d7e5f53789
Periodic harvest готовых НСПД ИРД-слоёв (ЗОУИТ 37577-581, ПЗЗ-границы 875838,
ОКН 875840, ООПТ/леса/вода 875845/866/832/835) по кварталам ЕКБ (66:41:* из
cad_parcels) → grid-walk → upsert ird_overlays (м.132) по (source_layer_id,
geom_data_id). Геометрия 3857→4326. content_* НЕ трогаем (резолвер D9). SAVEPOINT
per-feature; сбой квартала/слоя изолирован. Beat: ird-harvest-weekly (Mon 05:00 МСК).

Refs #1067 (B5). Тесты: 3 passed.
lekss361 added the
status/review
label 2026-06-06 18:46:13 +00:00
bot-reviewer reviewed 2026-06-06 18:51:56 +00:00
bot-reviewer left a comment
Collaborator

APPROVE

Keystone harvest-task связывает ird_overlays (м.132) ← nspd_client. Проверено досканально:

  • Все 11 LAYERS-ключей существуют в LAYERS dict (zouit_okn/engineering/natural/protected/other=37577-81, territorial_zones=875838, okn_territory=875840, protected_areas=875845, forestries=875866, coast_lines_river/sea=875832/35); несуществующий → warning+skip, не падает.
  • Сигнатуры подтверждены на main: search_by_cad(cad, thematic_id=2), qres.first (@property), get_features_in_bbox_grid(layer_id, bbox), _geojson_bbox_3857 (module-level, None→continue).
  • SAVEPOINT per-feature (begin_nested + try/except) зеркалит supply_layers_refresh.py; commit один раз; SessionLocal() try/finally close. Битая фича / int(geom_data_id) ValueError / CHECK geom_data_id>0 — изолированы SAVEPOINT'ом.
  • psycopg v3: все CAST(:x AS type), ни одного ::. INSERT-колонки = DDL м.132; content_* исключены из ON CONFLICT (резолвер D9 не перетирается).
  • Beat 0 5 * * mon_parse_cron поддерживает mon (5 существующих задач), 05:00 свободно (scrape_kn 04:15 / supply 06:00). celery_app.include корректен.

Advisory (не блок): scale ~400-600 кварталов × 11 слоёв × grid (~1.5ч weekly) — NSPDBulkClient уже throttle'ит rate_ms=600; прод-прогон деферится в B6 smoke. Приватный импорт _geojson_bbox_3857 — приемлемо at scale.

Merge → deploy-verify.

<!-- gendesign-review-bot: sha=d7e5f53 verdict=approve --> ✅ **APPROVE** Keystone harvest-task связывает ird_overlays (м.132) ← nspd_client. Проверено досканально: - **Все 11 LAYERS-ключей существуют** в `LAYERS` dict (zouit_okn/engineering/natural/protected/other=37577-81, territorial_zones=875838, okn_territory=875840, protected_areas=875845, forestries=875866, coast_lines_river/sea=875832/35); несуществующий → warning+skip, не падает. - Сигнатуры подтверждены на main: `search_by_cad(cad, thematic_id=2)`, `qres.first` (@property), `get_features_in_bbox_grid(layer_id, bbox)`, `_geojson_bbox_3857` (module-level, None→continue). - **SAVEPOINT per-feature** (`begin_nested` + try/except) зеркалит `supply_layers_refresh.py`; commit один раз; `SessionLocal()` try/finally close. Битая фича / `int(geom_data_id)` ValueError / CHECK geom_data_id>0 — изолированы SAVEPOINT'ом. - **psycopg v3**: все `CAST(:x AS type)`, ни одного `::`. INSERT-колонки = DDL м.132; content_* исключены из ON CONFLICT (резолвер D9 не перетирается). - Beat `0 5 * * mon` — `_parse_cron` поддерживает `mon` (5 существующих задач), 05:00 свободно (scrape_kn 04:15 / supply 06:00). celery_app.include корректен. **Advisory (не блок):** scale ~400-600 кварталов × 11 слоёв × grid (~1.5ч weekly) — NSPDBulkClient уже throttle'ит rate_ms=600; прод-прогон деферится в B6 smoke. Приватный импорт `_geojson_bbox_3857` — приемлемо at scale. Merge → deploy-verify.
bot-reviewer merged commit a15265c594 into main 2026-06-06 18:52:04 +00:00
Sign in to join this conversation.
No reviewers
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#1090
No description provided.