fix(tradein): понижать статус только у прогона, который работу сделал (#3288)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
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 4m59s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
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 4m59s
Прошлая правка понижала banned→failed/done по одному диагнозу infra и ломала обратный контракт: нулевой прогон с infra (yandex 5xx #3196, финализатор #2764) получал 'failed' — настоящий бан площадки, опознанный как infra, прятался под «нашу поломку». Хуже исходного дефекта: 2 красных теста в полном прогоне. Понижение сужено до случая прогона 5425 — dominant='infra' И produced > 0: брейкер оборвал по доле, а карточки при этом обогащались → 'done'. Нулевой прогон остаётся 'banned' (честность несёт ban_kind), пустая перепись — тем более: dominant='unknown', статус не трогаем. Тесты: контроль на обратную ошибку (ноль результата → banned+infra) и на пустой census (→ banned+unknown); основной кейс {'infra': 20} при 10 обогащённых — не banned.
This commit is contained in:
parent
1a693192e1
commit
c82ec7c3af
2 changed files with 56 additions and 24 deletions
|
|
@ -919,26 +919,27 @@ def mark_backfill_finished(
|
|||
counters["ban_kinds"] = dict(census) # type: ignore[assignment]
|
||||
dominant = _dominant_ban_kind(census)
|
||||
|
||||
if dominant == BAN_KIND_INFRA:
|
||||
if dominant == BAN_KIND_INFRA and produced > 0:
|
||||
# #3288: 'banned' означает «площадка нас заблокировала» — и читается так
|
||||
# же (триггер ротации IP, алерты, разбор простоя). Прогон, у которого
|
||||
# доминирует infra, показывает обратное: отказал НАШ тракт (сайдкар не
|
||||
# отдал страницу), площадка при этом молчала или вообще отвечала — прогон
|
||||
# 5425 при 41 infra из 48 «блоков» честно обогатил 41 карточку и всё равно
|
||||
# рапортовал «остановлен блоками источника». Диагноз уже посчитан
|
||||
# (_dominant_ban_kind), здесь он впервые влияет на СТАТУС: не 'banned', а
|
||||
# обычные правила ниже — 'failed' при нулевом результате (наша поломка,
|
||||
# это она и есть) и 'done', если прогон всё-таки что-то обогатил.
|
||||
# же (триггер ротации IP, алерты, разбор простоя). Прогон 5425 при 41
|
||||
# infra из 48 «блоков» честно обогатил 41 карточку — его оборвал брейкер
|
||||
# по доле, а не площадка, — и всё равно рапортовал «остановлен блоками
|
||||
# источника». Понижаем ровно этот случай: диагноз infra И прогон работу
|
||||
# сделал → 'done'.
|
||||
#
|
||||
# Нулевой прогон с infra остаётся 'banned' — контракт #2764/#3196:
|
||||
# там диагноз несёт ban_kind строки ('infra'), а статус говорит «прогон
|
||||
# оборван отказами». Понижать его до 'failed' по одному лишь диагнозу
|
||||
# опаснее исходного дефекта: при пустом/отсутствующем census (источник
|
||||
# видов не различает) dominant='unknown', а настоящий бан площадки,
|
||||
# опознанный как infra по 5xx, спрятался бы под «нашей поломкой».
|
||||
reason = (
|
||||
f"backfill-honest-status: {source} остановлен отказами НАШЕГО тракта — "
|
||||
f"blocked={blocked} (диагноз '{BAN_KIND_INFRA}' у большинства), "
|
||||
f"backfill-honest-status: {source} оборван брейкером на отказах НАШЕГО "
|
||||
f"тракта — blocked={blocked} (диагноз '{BAN_KIND_INFRA}' у большинства), "
|
||||
f"обогащено {enriched} из {attempted} попыток{hint} (#3288)"
|
||||
)
|
||||
logger.error("%s run_id=%d", reason, run_id)
|
||||
if produced == 0:
|
||||
mark_failed(db, run_id, reason, counters)
|
||||
else:
|
||||
mark_done(db, run_id, counters)
|
||||
mark_done(db, run_id, counters)
|
||||
return
|
||||
|
||||
reason = (
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@ from scraper_kit.proxy_errors import NoProxyAvailableError # noqa: E402
|
|||
|
||||
from app.services import scrape_runs as runs_svc # noqa: E402
|
||||
from app.services.backfill_block_breaker import BlockRatioBreaker # noqa: E402
|
||||
from app.services.scrape_runs import BAN_KIND_INFRA, BAN_KIND_PLATFORM # noqa: E402
|
||||
from app.services.scrape_runs import ( # noqa: E402
|
||||
BAN_KIND_INFRA,
|
||||
BAN_KIND_PLATFORM,
|
||||
BAN_KIND_UNKNOWN,
|
||||
)
|
||||
from app.tasks.avito_detail_backfill import ( # noqa: E402
|
||||
AvitoDetailBackfillResult,
|
||||
run_avito_detail_backfill,
|
||||
|
|
@ -315,17 +319,44 @@ def test_infra_dominant_run_is_not_marked_banned() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_infra_dominant_run_without_result_is_failed() -> None:
|
||||
"""Тот же диагноз, но ноль результата — это наша поломка: 'failed'."""
|
||||
def test_pure_infra_run_with_result_is_not_banned() -> None:
|
||||
"""Основной кейс без примеси: перепись целиком infra, карточки есть → не 'banned'."""
|
||||
banned, failed, done = _finish({BAN_KIND_INFRA: 20}, enriched=10)
|
||||
|
||||
assert (banned.call_count, failed.call_count, done.call_count) == (0, 0, 1), (
|
||||
f"mark_banned={banned.call_count} mark_failed={failed.call_count} "
|
||||
f"mark_done={done.call_count}: 20 отказов сайдкара при 10 обогащённых — 'done'"
|
||||
)
|
||||
|
||||
|
||||
def test_infra_dominant_run_without_result_stays_banned() -> None:
|
||||
"""Контроль на ОБРАТНУЮ ошибку: ноль результата — по-прежнему 'banned' (#2764/#3196).
|
||||
|
||||
Диагноз infra на нулевом прогоне неотличим от бана площадки, опознанного по 5xx
|
||||
(yandex, #3196): статус остаётся 'banned', честность несёт ban_kind. Понижение
|
||||
до 'failed' прятало бы настоящий бан под «нашу поломку» — падало 2 теста CI.
|
||||
"""
|
||||
banned, failed, done = _finish({BAN_KIND_INFRA: 41, BAN_KIND_PLATFORM: 7}, enriched=0)
|
||||
|
||||
assert banned.call_count == 0, "'banned' при доминирующем infra"
|
||||
assert (failed.call_count, done.call_count) == (1, 0), (
|
||||
f"mark_failed={failed.call_count} mark_done={done.call_count}: 0 обогащено "
|
||||
"отказами нашего тракта — 'failed', не 'done'"
|
||||
assert (banned.call_count, failed.call_count, done.call_count) == (1, 0, 0), (
|
||||
f"mark_banned={banned.call_count} mark_failed={failed.call_count} "
|
||||
f"mark_done={done.call_count}: нулевой прогон обязан остаться 'banned'"
|
||||
)
|
||||
assert BAN_KIND_INFRA in failed.call_args.args[2], (
|
||||
f"причина={failed.call_args.args[2]!r}: статус обязан назвать диагноз"
|
||||
assert banned.call_args.kwargs["ban_kind"] == BAN_KIND_INFRA, (
|
||||
f"ban_kind={banned.call_args.kwargs['ban_kind']!r}: диагноз обязан доехать"
|
||||
)
|
||||
|
||||
|
||||
def test_run_without_census_stays_banned() -> None:
|
||||
"""Источник видов не различает (ban_kinds пуст) → прежнее поведение: 'banned'."""
|
||||
banned, failed, done = _finish({}, enriched=41)
|
||||
|
||||
assert (banned.call_count, failed.call_count, done.call_count) == (1, 0, 0), (
|
||||
f"mark_banned={banned.call_count} mark_failed={failed.call_count} "
|
||||
f"mark_done={done.call_count}: без переписи диагноза нет — статус не меняем"
|
||||
)
|
||||
assert banned.call_args.kwargs["ban_kind"] == BAN_KIND_UNKNOWN, (
|
||||
f"ban_kind={banned.call_args.kwargs['ban_kind']!r}, ожидали 'unknown'"
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue