Commit graph

3 commits

Author SHA1 Message Date
b64e824e17 fix(tradein/sber): сторож мерит отставание загрузки, а не календарь (#2846)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m24s
Порог свежести якоря был недостижим по построению. period_month — метка ПЕРВОГО
числа месяца, поэтому возрасту ≥30 уже на закрытии месяца; плюс лаг публикации
источника. За 31 сутки прямых наблюдений монитора (07-13…08-12, scrape_runs.counters)
возраст лежал в 46..76 и ни разу не опускался ниже 46 — при пороге оценщика 35.
Сторож был истинным 100% времени с рождения таблицы и нёс ноль бит: при живом
источнике и при мёртвом загрузчике он писал одно и то же.

Второй порог (монитор, 60 = 35 + запас 25) не лучше: он лежит ВНУТРИ рабочего
диапазона. Обещание миграции 212 («такт 7 ⇒ потолок возраста 53 < 60») прод
ОПРОВЕРГ — 2026-08-12 возраст 72 при полном прогоне загрузки 08-06; двенадцатые
сутки подряд ERROR при исправной загрузке. Потолок 53 держался бы, только если бы
источник публиковал строго помесячно.

Что теперь. Загрузчик тянет ВСЮ серию (limit=1000&offset=0), поэтому после прогона
с errors=0 AND upserted>0 наш max(period_month) равен максимуму источника ПО
ПОСТРОЕНИЮ. Значит вопрос «отстали ли мы» = «давно ли был последний ЗАВЕДОМО ПОЛНЫЙ
прогон», и он не зависит от возраста периода. Порог — 2 такта самой загрузки,
читается из scrape_schedules.default_params.interval_days, то есть из той же строки,
по которой планировщик считает next_run_at: разъехаться с тактом он не может.
status='done' за успех не считается — прогон id=37 имеет done при {errors: 9,
upserted: 0}. Табло спрашивается тем же порядком, что у оценщика
(SBER_COEFF_DASHBOARDS), потому что max() по таблице маскирует отставшее табло:
real_estate_deals 2026-06, dinamika-tsen-obyavlenii 2026-05.

Два порога сведены удалением: settings.sber_index_max_age_days и per-estimate
warning в estimator убраны, свежесть считает ровно одно место.

fetched_at больше не переписывается апсертом. Забор идёт всей серией, поэтому
fetched_at = now() в DO UPDATE ставил одну метку всем 639 строкам, включая период
2017-01 — как признак свежести колонка была пуста. Теперь она означает «когда
впервые увидели период», т.е. такт публикации источника станет измеримым.
Ретроспективу это не возвращает: у уже лежащих строк метка 2026-08-06 и останется.

Refs #2846
2026-08-13 00:25:53 +05:00
3e1b9a8b0d fix(tradein): чинит такт загрузки СберИндекса — иначе новый ERROR стал бы ложной тревогой (#2674)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m59s
CI / changes (pull_request) Successful in 7s
Ревью PR #2681 опровергло исходную посылку по СберИндексу, и это подтвердилось
на моих же числах (все 24 прогона монитора, read-only):

  13-16.07  alert=1  age 73..76  latest=май
  17.07     alert=0  age 46      latest=июнь  ← день загрузки
  18-31.07  alert=0  age 47..60
  01-05.08  alert=1  age 61..65

Загрузка ходила раз в 28 дней и приносила период на месяц новее, возраст
считается от первого числа покрытого месяца → пол 46, потолок 74, порог 60
ВНУТРИ диапазона. Тревога срабатывала 14 суток из 28 без всякого застоя
источника: девять срабатываний были замером нашего собственного такта. Поднятие
до ERROR без этой правки завело бы ежедневное ложное событие две недели в месяц.

Миграция 212 переводит sber_index_pull на недельный такт (потолок ≈53 при пороге
60, запас 7 суток) вместо поднятия порога до 75 (запас 1 сутки — ломается от
любого сдвига окна). Цена: 9 запросов в неделю вместо 9 в 28 дней к публичному
sberindex.ru/api/sowa; прогон 4 секунды, 0 ошибок за всю историю.

Дополнительно по ревью:
- поллер Росреестра: ветка «файл найден в листинге, но HEAD не отдал zip» →
  ERROR (ровно поведение старой Bitrix-заглушки) + вписана в таблицу уровней;
- тестовый харнесс закрывает клиент событий (фоновый поток на каждый тест).

Refs #2674
2026-08-06 02:53:26 +05:00
46bbb79881 fix(tradein): сигналы о сбоях наконец становятся событиями, а протухание кук предупреждает заранее (#2674)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m58s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
В скрапер-контейнере GlitchTip поднят с LoggingIntegration(event_level=ERROR),
поэтому любой сигнал уровня WARNING событием не становится — сколько бы раз он
ни срабатывал. Прод это подтвердил: монитор устаревания СберИндекса отработал
24 раза, 9 из них со staleness-вердиктом, событий ноль; куки Домклика протухли
2026-08-03 и об этом никто не узнал.

Разбирали не «поменять warning на error», а по каждому сигналу: сбой, из-за
которого данные перестают обновляться — событие; рутина и ожидаемые состояния —
лог. Плюс предупреждение ЗАРАНЕЕ там, где чинить нужно руками (куки Домклика —
по образцу #2658 для Циана, переиспользован тот же подход session_expires_at +
COOKIE_EXPIRY_WARN_DAYS).

У поллера Росреестра выход нового квартала оставлен уровнем info, но получил
явный capture_message(level="info"): новость хорошая, но требует ручного импорта
оператором, а INFO-строка живёт только до ближайшего редеплоя. logger.error для
неё был бы враньём в error-rate и стрик-алертах.

Оговорка: у GlitchTip-проекта сейчас нет ни правил, ни получателей (#2673) —
события станут видны в интерфейсе, но никому не отправятся.

Refs #2674
2026-08-06 02:29:11 +05:00