"""Celery tasks для регулярного refresh аналитических метрик. Расписание задаётся в celery_app.beat_schedule. Сейчас: - refresh_ekb_districts_medians — раз в месяц 5-го числа в 04:00 МСК (после публикации последнего rosreestr-квартала + NSPD beat-cycle). """ from __future__ import annotations import logging from typing import Any from app.core.db import SessionLocal from app.services.analytics_refresh import refresh_ekb_districts_median from app.workers.celery_app import celery_app logger = logging.getLogger(__name__) @celery_app.task( bind=True, name="tasks.refresh_analytics.refresh_ekb_districts_medians", max_retries=2, ) def refresh_ekb_districts_medians( self: Any, window_months: int = 24, min_deals: int = 50, ) -> dict[str, Any]: """Refresh ekb_districts.median_price_per_m2 + mean_price_per_m2. Лёгкая задача (1-2 секунды на 8 районов), не требует locks. Запускается ежемесячно. Возвращает результат для аудита (что обновлено). """ db = SessionLocal() try: rows = refresh_ekb_districts_median(db, window_months=window_months, min_deals=min_deals) logger.info("refreshed %d districts", len(rows)) return { "updated_count": len(rows), "districts": rows, "window_months": window_months, "min_deals": min_deals, } except Exception as e: logger.exception("refresh_ekb_districts_medians failed: %s", e) raise finally: db.close()