fix(beat): distinguish DB-unreachable from intentional-empty schedule #520

Merged
lekss361 merged 2 commits from fix/beat-fallback-distinguish-empty into main 2026-05-24 13:14:12 +00:00

2 commits

Author SHA1 Message Date
lekss361
cca7dcd029 fix(beat): cleanup dead-code from prior fallback distinguishing — align with reality
Some checks failed
CI / backend (pull_request) Failing after 46s
CI / frontend (pull_request) Successful in 1m44s
Review-bot PR #520 SHA dc1cd94 нашёл medium discrepancy: `get_all` НЕ raises
на DB unreachable — оно catches Exception и возвращает _DEFAULTS (4 synthetic
rows, scrape_kn + objective_sync enabled). Значит `except` блок в
build_beat_schedule и `rows_seen == 0` branch — dead code, никогда не fires.

Primary fix всё равно работает (operator-disable создаёт реальные rows c
enabled=false → loop их skip'ает → schedule={} → respect). Но контракт в
docstring ("strict, raises on failure") был fiction.

Cleanup (Option A из review):
- Убрана try/except в build_beat_schedule (dead — get_all не raises)
- Убрана rows_seen == 0 branch (dead — get_all всегда returns >=4 rows из _DEFAULTS)
- Сигнатура `_build_beat_schedule_from_db` обратно `-> dict` (не tuple)
- Docstring переписан под реальное поведение: schedule пуст ТОЛЬКО при
  operator-initiated disable; DB-unreachable case замаскирован под _DEFAULTS
  (синонимично env-fallback по итогу: scrape_kn + objective_sync с дефолтным cron)

Net behavior identical для всех 4 сценариев (operator-disable, normal-config,
DB-unreachable, fresh-install) — но код теперь честный.
2026-05-24 16:10:48 +03:00
lekss361
dc1cd943e6 fix(beat): distinguish DB-unreachable from intentional-empty schedule
Some checks failed
CI / backend (pull_request) Failing after 41s
CI / frontend (pull_request) Successful in 1m42s
UPDATE job_settings SET enabled=false для всех cron-able jobs приводил к
пустому schedule из DB — caller (build_beat_schedule) интерпретировал
'not schedule' как 'DB error' и срывался на env-based fallback, который
повторно добавлял scrape_kn + objective_sync из settings.scrape_kn_cron /
objective_sync_cron. Disable через DB был **бесполезен**.

Incident 2026-05-24: WAF hard-ban на VPS IP от DOM.РФ → попытка отключить
scrape_kn + objective_sync через UPDATE job_settings — fallback вернул их
обратно. Беспорядок виден в beat logs: 'beat_schedule: строим fallback из
env vars' при наличии rows в БД.

Fix:
- `_build_beat_schedule_from_db` теперь использует `get_all` (strict, raises)
  вместо `get_all_safe` (silently возвращает _DEFAULTS)
- Возвращает (schedule, rows_seen) tuple
- Caller fallback'ает ТОЛЬКО при `not db_reachable` (exception) ИЛИ
  `rows_seen == 0` (fresh install, безопасный fallback для setup)
- При rows_seen > 0 + schedule={} — RESPECT user intent (все disabled)
- Hardcoded entries (OSM POI/noise, nspd cleanup, refresh_analytics)
  добавляются ВСЕГДА сверху — они не управляются job_settings
2026-05-24 15:56:31 +03:00