fix(workers): schedule mv_layout_velocity refresh (#1666) #1669
3 changed files with 64 additions and 0 deletions
|
|
@ -506,4 +506,20 @@ def build_beat_schedule() -> dict:
|
|||
"options": {"queue": "celery"},
|
||||
}
|
||||
|
||||
# Refresh mv_layout_velocity (#1666) — питает «лучшие планировки» best_layouts (#113).
|
||||
# До этого MV рефрешился ТОЛЬКО ручным вызовом refresh_layout_velocity() → в проде
|
||||
# данные молча устаревали. REFRESH ... CONCURRENTLY (non-blocking) по mv_layout_velocity.
|
||||
#
|
||||
# Воскресенье 03:00 МСК (Celery conf.timezone=Europe/Moscow → crontab в МСК, #1233).
|
||||
# Намеренно ВНЕ monday-кластера тяжёлых site_finder-рефрешей (scrape_kn 04:15,
|
||||
# ird 05:00, gknspecial 05:30, supply-layers 06:00, genplan 06:30, location 07:00) и
|
||||
# вне воскресного okn-objects (04:30) — час запаса, не конкурирует за БД/CPU.
|
||||
# MV агрегирует темпы вымывания планировок (меняются медленно) → еженедельно хватает.
|
||||
# Техническая infra-задача, не в job_settings (как refresh-quarter-price-index / supply-layers).
|
||||
schedule["refresh-layout-velocity"] = {
|
||||
"task": "tasks.refresh_layout_velocity.refresh_layout_velocity",
|
||||
"schedule": _parse_cron("0 3 * * sun"), # 03:00 MSK, воскресенье
|
||||
"options": {"queue": "celery"},
|
||||
}
|
||||
|
||||
return schedule
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ celery_app = Celery(
|
|||
"app.workers.tasks.pat_subzones_load",
|
||||
"app.workers.tasks.izyatie_ocr_ingest",
|
||||
"app.workers.tasks.developer_registry_refresh",
|
||||
"app.workers.tasks.refresh_layout_velocity",
|
||||
],
|
||||
)
|
||||
celery_app.conf.timezone = "Europe/Moscow"
|
||||
|
|
|
|||
47
backend/app/workers/tasks/refresh_layout_velocity.py
Normal file
47
backend/app/workers/tasks/refresh_layout_velocity.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
"""Celery task: refresh mv_layout_velocity (питает «лучшие планировки» best_layouts).
|
||||
|
||||
Scheduled via hardcoded beat entry in workers/beat_schedule.py:
|
||||
'refresh-layout-velocity' — weekly on Sunday at 03:00 MSK.
|
||||
Стоит в «ночном» окне воскресенья, отдельно от monday-кластера тяжёлых
|
||||
site_finder-рефрешей (supply-layers / ird / gknspecial / cbr и т.д.), чтобы
|
||||
не конкурировать с ними за БД/CPU.
|
||||
|
||||
Issue: #1666 (рефреш не был подключён в beat → данные best_layouts молча
|
||||
устаревали в проде). MV-источник: #113 (PR B, mv_layout_velocity → best_layouts).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from app.core.db import SessionLocal
|
||||
from app.services.site_finder.layout_velocity_refresh import refresh_layout_velocity
|
||||
from app.workers.celery_app import celery_app
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@celery_app.task(
|
||||
bind=True,
|
||||
name="tasks.refresh_layout_velocity.refresh_layout_velocity",
|
||||
max_retries=2,
|
||||
)
|
||||
def refresh_layout_velocity_task(self: Any) -> dict[str, Any]:
|
||||
"""REFRESH MATERIALIZED VIEW mv_layout_velocity (best_layouts, #113 / #1666).
|
||||
|
||||
MV рефрешится CONCURRENTLY (non-blocking, требует unique-индекс
|
||||
mv_layout_velocity_pk); сервис сам падает в non-concurrent при unpopulated MV.
|
||||
|
||||
Returns result dict for Celery task result store / logging.
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
count = refresh_layout_velocity(db, concurrently=True)
|
||||
logger.info("refresh_layout_velocity: completed, mv rows=%d", count)
|
||||
return {"status": "ok", "mv_layout_velocity_rows": count}
|
||||
except Exception as e:
|
||||
logger.exception("refresh_layout_velocity failed: %s", e)
|
||||
raise
|
||||
finally:
|
||||
db.close()
|
||||
Loading…
Add table
Reference in a new issue