fix(tradein/observability): результат detail-бэкфиллов доезжает до total_seen (#3044) #3096
3 changed files with 87 additions and 2 deletions
|
|
@ -391,7 +391,20 @@ def _column_counts(counters: dict[str, int]) -> tuple[int | None, int | None]:
|
|||
Возвращает (total_seen, new_count); None для ключа, которого нет в counters —
|
||||
тогда соответствующая колонка не перезаписывается (COALESCE-семантика в UPDATE).
|
||||
"""
|
||||
return _run_result_count(counters), _pick_int(
|
||||
# #3044: detail-бэкфиллы (avito/yandex/domclick_detail_backfill) пишут свой
|
||||
# результат ТОЛЬКО ключом 'enriched' — колонка total_seen у них оставалась 0
|
||||
# навсегда, и замер в issue прочитал «обогащено 0 за 7 дней» при реальных 801
|
||||
# (listings.detail_enriched_at). 'enriched' — фолбэк ИМЕННО ЗДЕСЬ, а не в
|
||||
# _RESULT_COUNTER_KEYS: тот список кормит ещё и zero-result-стрик, где
|
||||
# «догнавший очередь» бэкфилл (attempted=0, enriched=0) стал бы измеренным
|
||||
# нулём и копил бы непрерываемый стрик — ровно та ловушка, за которую ревью
|
||||
# выкинуло из списка голый 'rows_inserted' (см. test_rosreestr_dkp_import_
|
||||
# healthy_zero_stays_unmeasured). Витринной колонке фолбэк безопасен: она не
|
||||
# участвует в стриках (#2703 читает counters, не колонку).
|
||||
total_seen = _run_result_count(counters)
|
||||
if total_seen is None:
|
||||
total_seen = _pick_int(counters, "enriched")
|
||||
return total_seen, _pick_int(
|
||||
counters, "new_count", "lots_inserted", "saved_inserted", "rows_inserted"
|
||||
)
|
||||
|
||||
|
|
|
|||
59
tradein-mvp/backend/tests/test_3044_enriched_result_key.py
Normal file
59
tradein-mvp/backend/tests/test_3044_enriched_result_key.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"""#3044 (наблюдаемость): результат detail-бэкфиллов виден колонке total_seen.
|
||||
|
||||
Прод-факт (Poincare, 26.08.2026): avito_detail_backfill за 7 дней — 36 прогонов,
|
||||
sum(total_seen)=0, из чего замер в issue сделал вывод «обогащено 0». Реально:
|
||||
counters={'enriched': 61, ...} у прогона 25.08 09:18, а listings.detail_enriched_at
|
||||
насчитал 801 обогащение за те же 7 дней. Джобы пишут результат ТОЛЬКО ключом
|
||||
'enriched', которого _column_counts не знал — колонка не заполнялась ни у done,
|
||||
ни у banned прогонов, и «провал и успех писали один и тот же признак» (ноль).
|
||||
|
||||
Фикс: 'enriched'-фолбэк в _column_counts (обе копии: app и scraper-kit) — только
|
||||
для витринной колонки. В _RESULT_COUNTER_KEYS ключ НЕ добавлен намеренно: тот
|
||||
список кормит zero-result-стрик, где догнавший очередь бэкфилл (attempted=0)
|
||||
стал бы непрерываемым измеренным нулём — ловушка, за которую ревью уже выкинуло
|
||||
из списка 'rows_inserted' (#2703, test_rosreestr_dkp_import_healthy_zero_*).
|
||||
|
||||
Тесты колонки красные на origin/main по ЗНАЧЕНИЮ (None вместо 61), не по импорту.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from scraper_kit.orchestration import runs as kit_runs
|
||||
|
||||
from app.services import scrape_runs as app_runs
|
||||
|
||||
# Прод-прогон avito_detail_backfill 25.08 09:18 UTC (баном оборван, но 61 обогащён).
|
||||
_AVITO_BANNED_RUN = {
|
||||
"gone": 0,
|
||||
"failed": 0,
|
||||
"blocked": 39,
|
||||
"enriched": 61,
|
||||
"attempted": 100,
|
||||
"duration_sec": 1600,
|
||||
}
|
||||
|
||||
|
||||
def test_column_counts_fills_total_seen_for_detail_backfill() -> None:
|
||||
"""_column_counts — ровно тот путь, которым mark_done/mark_banned пишут
|
||||
выделенные колонки. До фикса: (None, None) → total_seen вечно 0."""
|
||||
for mod in (app_runs, kit_runs):
|
||||
total_seen, new_count = mod._column_counts(_AVITO_BANNED_RUN)
|
||||
assert total_seen == 61
|
||||
assert new_count is None # ключей new_count/lots_inserted/... у бэкфилла нет
|
||||
|
||||
|
||||
def test_result_keys_win_over_enriched_fallback() -> None:
|
||||
"""У newbuilding_enrich рядом с 'enriched' лежит 'succeeded' — приоритет за ним:
|
||||
поведение источников с настоящим result-ключом не меняется."""
|
||||
for mod in (app_runs, kit_runs):
|
||||
total_seen, _ = mod._column_counts({"succeeded": 7, "enriched": 3})
|
||||
assert total_seen == 7
|
||||
|
||||
|
||||
def test_zero_streak_watchdog_semantics_untouched() -> None:
|
||||
"""Контракт #2703 сохранён: для стрик-сторожа 'enriched' НЕ результатная
|
||||
метрика — догнавший очередь бэкфилл остаётся «не измерено» и стрик не копит.
|
||||
Этот тест зелёный в обеих эрах (инвариант, а не фикс)."""
|
||||
for mod in (app_runs, kit_runs):
|
||||
assert mod._run_result_count({"attempted": 1600, "enriched": 0, "failed": 1600}) is None
|
||||
assert mod._run_result_count({"enriched": 61, "attempted": 100}) is None
|
||||
|
|
@ -391,7 +391,20 @@ def _column_counts(counters: dict[str, int]) -> tuple[int | None, int | None]:
|
|||
Возвращает (total_seen, new_count); None для ключа, которого нет в counters —
|
||||
тогда соответствующая колонка не перезаписывается (COALESCE-семантика в UPDATE).
|
||||
"""
|
||||
return _run_result_count(counters), _pick_int(
|
||||
# #3044: detail-бэкфиллы (avito/yandex/domclick_detail_backfill) пишут свой
|
||||
# результат ТОЛЬКО ключом 'enriched' — колонка total_seen у них оставалась 0
|
||||
# навсегда, и замер в issue прочитал «обогащено 0 за 7 дней» при реальных 801
|
||||
# (listings.detail_enriched_at). 'enriched' — фолбэк ИМЕННО ЗДЕСЬ, а не в
|
||||
# _RESULT_COUNTER_KEYS: тот список кормит ещё и zero-result-стрик, где
|
||||
# «догнавший очередь» бэкфилл (attempted=0, enriched=0) стал бы измеренным
|
||||
# нулём и копил бы непрерываемый стрик — ровно та ловушка, за которую ревью
|
||||
# выкинуло из списка голый 'rows_inserted' (см. test_rosreestr_dkp_import_
|
||||
# healthy_zero_stays_unmeasured). Витринной колонке фолбэк безопасен: она не
|
||||
# участвует в стриках (#2703 читает counters, не колонку).
|
||||
total_seen = _run_result_count(counters)
|
||||
if total_seen is None:
|
||||
total_seen = _pick_int(counters, "enriched")
|
||||
return total_seen, _pick_int(
|
||||
counters, "new_count", "lots_inserted", "saved_inserted", "rows_inserted"
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue