fix(beat): distinguish DB-unreachable from intentional-empty schedule #520
1 changed files with 31 additions and 20 deletions
|
|
@ -53,16 +53,28 @@ def _default_regions() -> list[int]:
|
|||
def _build_beat_schedule_from_db() -> dict:
|
||||
"""Строит beat_schedule из job_settings БД.
|
||||
|
||||
Возвращает пустой словарь при любой ошибке — caller добавит fallback.
|
||||
"""
|
||||
try:
|
||||
from app.core.db import SessionLocal
|
||||
from app.services.job_settings import get_all_safe
|
||||
Returns: schedule (может быть пустой если все enabled rows без cron или disabled).
|
||||
|
||||
rows = get_all_safe(SessionLocal)
|
||||
except Exception as e:
|
||||
logger.warning("build_beat_schedule: не удалось прочитать job_settings: %s", e)
|
||||
return {}
|
||||
`get_all` маскирует DB-unreachable case через возврат _DEFAULTS (4 synthetic
|
||||
rows, все enabled=True с дефолтными cron'ами) — это значит "DB unreachable" и
|
||||
"fresh install (table empty)" неотличимы от "normal с _DEFAULTS". В обоих
|
||||
случаях schedule НЕ будет пустым — _DEFAULTS дадут scrape_kn + objective_sync.
|
||||
|
||||
КРИТИЧНО для operator-disable scenario: когда DB reachable и оператор сделал
|
||||
`UPDATE job_settings SET enabled=false WHERE job_type IN (...)` — get_all
|
||||
вернёт реальные rows (НЕ _DEFAULTS), loop их пропустит → schedule={}. Caller
|
||||
(build_beat_schedule) НЕ должен срывался на env fallback в этом случае,
|
||||
иначе disable бесполезен. См. инцидент 2026-05-24 (WAF cooldown disable
|
||||
scrape_kn → old code fallback'ал scrape_kn обратно из env).
|
||||
"""
|
||||
from app.core.db import SessionLocal
|
||||
from app.services.job_settings import get_all
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
rows = get_all(db)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
schedule: dict = {}
|
||||
for row in rows:
|
||||
|
|
@ -168,19 +180,18 @@ def _build_beat_schedule_fallback() -> dict:
|
|||
|
||||
|
||||
def build_beat_schedule() -> dict:
|
||||
"""Строит beat_schedule: сначала из DB, при неудаче — fallback на env.
|
||||
"""Строит beat_schedule из DB (job_settings) + добавляет hardcoded entries.
|
||||
|
||||
Всегда добавляет refresh-ekb-districts-medians (нет в job_settings).
|
||||
`_build_beat_schedule_from_db` использует `get_all` который сам fallback'ает на
|
||||
_DEFAULTS при DB unreachable / fresh install → возвращает 4 synthetic rows
|
||||
(scrape_kn + objective_sync enabled). То есть schedule из DB-builder ПУСТ
|
||||
только когда оператор явно disabled все cron-able jobs через UPDATE
|
||||
job_settings — это **намерение**, респектим без env-fallback.
|
||||
|
||||
Hardcoded entries (refresh-analytics, OSM POI/noise, nspd cleanup) добавляются
|
||||
ВСЕГДА — они не управляются через job_settings.
|
||||
"""
|
||||
schedule: dict = {}
|
||||
try:
|
||||
schedule = _build_beat_schedule_from_db()
|
||||
except Exception as e:
|
||||
logger.error("build_beat_schedule: неожиданная ошибка: %s — fallback", e)
|
||||
|
||||
if not schedule:
|
||||
# БД пустая или недоступна — полный fallback
|
||||
return _build_beat_schedule_fallback()
|
||||
schedule = _build_beat_schedule_from_db()
|
||||
|
||||
# Всегда добавляем refresh_analytics (этот job нет в job_settings,
|
||||
# он технический и не требует конфигурации через UI).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue