gendesign/backend/app/workers/tasks/developer_registry_refresh.py
Light1YT b211183940
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / changes (push) Successful in 8s
CI / frontend-tests (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m33s
CI / backend-tests (pull_request) Successful in 6m33s
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 1m44s
Deploy / build-worker (push) Successful in 5m24s
Deploy / deploy (push) Successful in 1m30s
feat(site-finder): детерминированная атрибуция застройщика в analyze (#1088)
Сервис get_developer_attribution поверх fn_developer_for_parcel (миграция 149):
топ-1 застройщик участка + track-record (РНС/РВЭ + домрф) + nearby_developers.
Дедуп по норм-ИНН (лучший match_method первым). Wire в analyze additive без флага
(чистый DB-резолвер по индексам, graceful → None). Beat-refresh developer_registry
ежемесячно 05:30 МСК после ekburg-permits. Pydantic-схемы + 18 тестов.

Источники: ekburg_construction_permits (РНС, ИНН) ⋈ domrf_kn_objects по
нормализованному ИНН + spatial/quarter fallback. 68% domrf-застройщиков имеют РНС.
EXPLAIN: point-lookup 0.06ms, резолвер ~30ms (functional/GIST индексы в миграции).

Closes #1088
2026-06-13 16:13:45 +05:00

58 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Celery task: refresh developer_registry materialized view (#1088 «GG-форсайт»).
Вызывает ``fn_refresh_developer_registry()`` (миграция 149,
``data/sql/149_developer_attribution.sql``) — REFRESH MATERIALIZED VIEW CONCURRENTLY
``developer_registry`` (реестр застройщиков по норм-ИНН: канон-имя + track-record
permits+domrf). CONCURRENTLY не блокирует SELECT-читателей (analyze) во время refresh.
Scheduled via hardcoded beat entry в workers/beat_schedule.py:
'developer-registry-refresh-monthly' — ежемесячно 1-го числа в 05:30 МСК,
через 30 мин после 'ekburg-permits-monthly' (05:00 МСК), чтобы permits-сторона
реестра обновлялась на свежих РНС/РВЭ. domrf-сторона обновляется ежедневно
(scrape_kn), но ИНН/track-record застройщиков меняются редко — monthly refresh
реестра с запасом достаточно (резолвер всё равно читает domrf-quarter напрямую).
Issue: #1088.
"""
from __future__ import annotations
import logging
from typing import Any
from sqlalchemy import text
from app.core.db import SessionLocal
from app.workers.celery_app import celery_app
logger = logging.getLogger(__name__)
@celery_app.task(
bind=True,
name="tasks.developer_registry_refresh.refresh_developer_registry",
max_retries=2,
)
def refresh_developer_registry(self: Any) -> dict[str, Any]:
"""REFRESH MATERIALIZED VIEW CONCURRENTLY developer_registry.
Лёгкая задача (реестр ~1024 застройщика). CONCURRENTLY — non-blocking для
читателей analyze; требует unique-индекс uq_developer_registry_inn (создан
миграцией 149). Возвращает row-count реестра после refresh для observability.
Returns:
dict для Celery result store / логирования.
"""
db = SessionLocal()
try:
db.execute(text("SELECT fn_refresh_developer_registry()"))
db.commit()
row = db.execute(text("SELECT COUNT(*) FROM developer_registry")).first()
count = int(row[0]) if row else 0
logger.info("refresh_developer_registry: completed, developers=%d", count)
return {"status": "ok", "developer_registry_rows": count}
except Exception as e:
logger.exception("refresh_developer_registry failed: %s", e)
raise
finally:
db.close()