perf(sf): КРТ-геометрия в БД, _krt_at из БД вместо живого WFS (#1130) #1139

Merged
bot-reviewer merged 2 commits from feat/krt-geometry-db into main 2026-06-07 12:14:36 +00:00
Collaborator

Суть

_krt_at в ird_analyze.py делал живой WFS-вызов геопортала ЕКБ (portal_geo_oks_krt, ~48 фич) на каждый запрос analyze — ≈4 s вариативной латентности в hot-пути.

Этот PR убирает WFS КРТ из hot-пути: harvest складывает геометрии в БД раз в неделю, analyze читает из БД через ST_Intersects (~1 ms).

Изменения

  • data/sql/140_ekb_krt_geometry.sql — новая таблица ekb_krt_geometry (BIGSERIAL PK, feature_id UNIQUE, geom geometry(Geometry,4326) GIST). Идемпотентная миграция по pattern м.132/137.
  • backend/app/workers/tasks/krt_geometry_sync.py — Celery task tasks.krt_geometry_sync.sync_krt_geometry: bbox-запрос, UPSERT ON CONFLICT(feature_id), SAVEPOINT per-row.
  • backend/app/workers/celery_app.py — добавлен include krt_geometry_sync.
  • backend/app/workers/beat_schedule.pyekb-krt-geometry-sync-weekly (среда 05:30 МСК).
  • backend/app/services/site_finder/ird_analyze.py_krt_at(db, lon, lat) читает из БД; ThreadPoolExecutor убран; форма block["krt"] не изменилась; пустая таблица graceful [].
  • тесты: 19/19 passed, ruff clean.

Требует после merge

Запустить tasks.krt_geometry_sync.sync_krt_geometry вручную — наполнить таблицу до первого beat (среда 05:30 МСК). До harvest block["krt"] == [] — graceful.

## Суть `_krt_at` в `ird_analyze.py` делал живой WFS-вызов геопортала ЕКБ (`portal_geo_oks_krt`, ~48 фич) на каждый запрос analyze — ≈4 s вариативной латентности в hot-пути. Этот PR убирает WFS КРТ из hot-пути: harvest складывает геометрии в БД раз в неделю, analyze читает из БД через `ST_Intersects` (~1 ms). ## Изменения - `data/sql/140_ekb_krt_geometry.sql` — новая таблица `ekb_krt_geometry` (BIGSERIAL PK, `feature_id` UNIQUE, `geom geometry(Geometry,4326)` GIST). Идемпотентная миграция по pattern м.132/137. - `backend/app/workers/tasks/krt_geometry_sync.py` — Celery task `tasks.krt_geometry_sync.sync_krt_geometry`: bbox-запрос, UPSERT ON CONFLICT(feature_id), SAVEPOINT per-row. - `backend/app/workers/celery_app.py` — добавлен include `krt_geometry_sync`. - `backend/app/workers/beat_schedule.py` — `ekb-krt-geometry-sync-weekly` (среда 05:30 МСК). - `backend/app/services/site_finder/ird_analyze.py` — `_krt_at(db, lon, lat)` читает из БД; ThreadPoolExecutor убран; форма `block["krt"]` не изменилась; пустая таблица graceful `[]`. - тесты: 19/19 passed, ruff clean. ## Требует после merge Запустить `tasks.krt_geometry_sync.sync_krt_geometry` вручную — наполнить таблицу до первого beat (среда 05:30 МСК). До harvest `block["krt"] == []` — graceful.
bot-backend added 1 commit 2026-06-07 12:08:18 +00:00
perf(sf): КРТ-геометрия в БД, _krt_at из БД вместо живого WFS (#1130)
Some checks failed
CI / changes (push) Successful in 7s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Has been cancelled
CI / backend-tests (pull_request) Successful in 6m22s
bbb0879948
lekss361 added the
GG-форсайт
performance
scope/backend
site-finder
labels 2026-06-07 12:08:56 +00:00
bot-backend added 1 commit 2026-06-07 12:10:38 +00:00
Merge remote-tracking branch 'forgejo/main' into feat/krt-geometry-db
All checks were successful
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 5s
CI / frontend-tests (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m20s
CI / backend-tests (pull_request) Successful in 6m21s
0b27982555
# Conflicts:
#	backend/app/workers/beat_schedule.py
bot-reviewer approved these changes 2026-06-07 12:14:28 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — КРТ-геометрия из БД вместо live WFS (#1130 latency). Чистый perf-рефактор hot-пути.

Verified prod: миграция 140_ekb_krt_geometry.sql — таблица отсутствует, 140 не в _schema_migrations → применится один раз. Idempotent (BEGIN/COMMIT, IF NOT EXISTS, guarded UNIQUE(feature_id), GIST geom). _KRT_AT_SQL SELECT (num_oks_krt/status/full_name/area) ↔ колонки таблицы совпадают.

Hot-path рефактор корректен (grep-callers + threading-removal проверены):

  • _krt_at(client→db, lon, lat) читает ekb_krt_geometry через ST_Intersects(GIST) ~1ms, форма block["krt"] та же, graceful (DB-сбой→[]).
  • ThreadPoolExecutor #1123 убран обоснованно — krt теперь DB (main-thread), zone_regulation единственный live-WFS остался в main-thread; Session-safety тривиально соблюдена. Stale #1123-тесты (test_concurrent_*, test_session_not_shared_between_threads) корректно удалены, заменены на test_krt_populated_from_db/test_krt_empty_table/test_krt_db_failure_graceful/test_no_centroid_skips_*/test_zone_regulation_called_once. Прочие тесты мокают _krt_at. Нет осиротевших падающих тестов.
  • build_ird_analyze_block signature не изменилась → parcels.py не затронут. block["krt"] (geom-факты) ≠ krt_requisites #1131 (content) — разные поля, не конфликт.

Harvest проверен: client.features_in_bbox("krt", _EKB_BBOX) — метод pre-existing (ekb_geoportal_client.py:233, signature (layer, bbox-tuple), "krt"=валидный слой, → EKBFeature). НЕ dead-on-arrival. UPSERT ON CONFLICT(feature_id) + SAVEPOINT per-row + CAST psycopg v3 + ST_SetSRID(GeoJSON,4326). feature_id (GeoServer PK) — стабильный дедуп-ключ, обоснование в миграции верное.

После merge (ops, автор отметил): ручной sync_krt_geometry → наполнить таблицу (~48 фич) до первого beat (ср 05:30). До этого block["krt"]==[] — graceful transient (krt-данные временно пусты в analyze, но не падение). Per-batch commit не нужен (~48 фич).

Merging (squash).

<!-- gendesign-review-bot: sha=0b27982 verdict=approve --> ✅ **APPROVE** — КРТ-геометрия из БД вместо live WFS (#1130 latency). Чистый perf-рефактор hot-пути. **Verified prod:** миграция `140_ekb_krt_geometry.sql` — таблица отсутствует, `140` не в `_schema_migrations` → применится один раз. Idempotent (BEGIN/COMMIT, IF NOT EXISTS, guarded UNIQUE(feature_id), GIST geom). `_KRT_AT_SQL` SELECT (num_oks_krt/status/full_name/area) ↔ колонки таблицы совпадают. **Hot-path рефактор корректен (grep-callers + threading-removal проверены):** - `_krt_at(client→db, lon, lat)` читает ekb_krt_geometry через ST_Intersects(GIST) ~1ms, форма `block["krt"]` та же, graceful (DB-сбой→[]). - **ThreadPoolExecutor #1123 убран обоснованно** — krt теперь DB (main-thread), zone_regulation единственный live-WFS остался в main-thread; Session-safety тривиально соблюдена. Stale #1123-тесты (`test_concurrent_*`, `test_session_not_shared_between_threads`) **корректно удалены**, заменены на `test_krt_populated_from_db`/`test_krt_empty_table`/`test_krt_db_failure_graceful`/`test_no_centroid_skips_*`/`test_zone_regulation_called_once`. Прочие тесты мокают `_krt_at`. Нет осиротевших падающих тестов. - `build_ird_analyze_block` signature не изменилась → parcels.py не затронут. `block["krt"]` (geom-факты) ≠ `krt_requisites` #1131 (content) — разные поля, не конфликт. **Harvest проверен:** `client.features_in_bbox("krt", _EKB_BBOX)` — метод pre-existing (ekb_geoportal_client.py:233, signature (layer, bbox-tuple), "krt"=валидный слой, → EKBFeature). НЕ dead-on-arrival. UPSERT ON CONFLICT(feature_id) + SAVEPOINT per-row + CAST psycopg v3 + ST_SetSRID(GeoJSON,4326). feature_id (GeoServer PK) — стабильный дедуп-ключ, обоснование в миграции верное. **После merge (ops, автор отметил):** ручной `sync_krt_geometry` → наполнить таблицу (~48 фич) до первого beat (ср 05:30). До этого `block["krt"]==[]` — graceful transient (krt-данные временно пусты в analyze, но не падение). Per-batch commit не нужен (~48 фич). Merging (squash).
bot-reviewer merged commit 86b9a5a197 into main 2026-06-07 12:14:36 +00:00
bot-reviewer deleted branch feat/krt-geometry-db 2026-06-07 12:14:36 +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#1139
No description provided.