gendesign/backend/app/workers/tasks/gisogd_permits_sync.py
bot-backend 282c92747e
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 2m40s
Deploy / build-worker (push) Successful in 3m27s
Deploy / build-frontend (push) Successful in 4m0s
Deploy / deploy (push) Successful in 1m41s
feat(scrapers): реестр РНС/РВЭ ГИСОГД-СО из открытого API — миграция + лоадер (#2367 PR-1) (#2370)
2026-07-04 03:26:07 +00:00

69 lines
3.1 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: инкрементальная синхронизация реестра РНС/РВЭ ГИСОГД-СО (#2367).
Источник: открытый JSON-API gisogd66.midural.ru (раздел 13), БЕЗ авторизации и БЕЗ
гео-блока — задача может выполняться и локально, и на проде. Держим weekly (обновляется
ежедневно, но лоадер инкрементален и дёшев при отсутствии изменений). Persistent
breadcrumbs в nspd_geo_log (как connection_capacity_sync). Import-light: тяжёлый
загрузчик импортируется лениво внутри таска.
"""
import logging
from sqlalchemy import text
from app.workers.celery_app import celery_app
logger = logging.getLogger(__name__)
def _log_breadcrumb(stage: str, level: str, message: str) -> None:
"""Записать строку в nspd_geo_log (job_id=NULL) — диагностика без SSH."""
try:
from app.core.db import SessionLocal
db = SessionLocal()
try:
db.execute(
text(
"INSERT INTO nspd_geo_log (job_id, level, stage, message) "
"VALUES (NULL, :lvl, :stage, :msg)"
),
{"lvl": level, "stage": stage, "msg": message[:500]},
)
db.commit()
finally:
db.close()
except Exception as e:
logger.warning("gisogd_permits breadcrumb failed: %s", e)
@celery_app.task(
name="tasks.gisogd_permits_sync.sync_gisogd_permits",
queue="celery",
# Холодный прогон ~6k карточек (2 схемы × RS+RV) при politeness-sleep укладывается
# в ~25 мин; щедрый лимит по конвенции full_report/forecast, чтобы beat-ран не убили
# mid-upsert. Инкрементальные прогоны — минуты.
time_limit=3600,
soft_time_limit=3300,
)
def sync_gisogd_permits() -> dict:
"""Инкрементально загрузить РНС/РВЭ ГИСОГД-СО (обе схемы, обе группы) → gisogd_permits.
Список группы → сверка с БД по (source_key, date_reg) → карточки только для
новых/изменившихся → UPSERT по (doc_group, doc_num) с предпочтением позднего date_reg.
Returns: счётчики {listed, fetched_details, inserted, updated, skipped_unchanged,
no_cad, no_geom}.
"""
_log_breadcrumb("gisogd_permits_sync", "info", "task started")
try:
from app.services.scrapers.gisogd66 import load_gisogd_permits
result = load_gisogd_permits()
logger.info("sync_gisogd_permits done: %s", result)
_log_breadcrumb("gisogd_permits_sync", "info", f"done: {result}")
return result
except Exception as e:
logger.exception("sync_gisogd_permits failed: %s", e)
_log_breadcrumb("gisogd_permits_sync", "error", f"{type(e).__name__}: {e}")
raise