fix(tradein/scraper): статус «забанен» перестаёт выдавать наш сбой за чужой (#2686) #2711
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2711
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/2686-ban-split-and-alerts"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Из 115 avito-прогонов со статусом
banned(прод, 2026-08-06):browser unavailable/browser-sidecar error)Avito SERP firewall … IP banned)Оба исхода писали разный текст ошибки и получали один статус. Классификатору не нужен новый источник знания — надо перестать схлопывать.
Механизм разведения — поле причины, не новый статус
AvitoSidecarUnavailableError— подтипAvitoRateLimitedError, поднимается в единственном месте, где отказ порождён нашей инфраструктурой (providers/avito/serp.py, веткаexcept (HTTPStatusError, TimeoutException, TransportError)вокругbrowser.fetch). Подтип, а не отдельный класс: всеexcept (AvitoBlockedError, AvitoRateLimitedError)продолжают ловить его без правок — иначе прогон ушёл бы вmark_failedи потерял чекпоинт.scrape_runs.ban_kind(platform|infra, миграция 218) — рядом соstatus='banned', а не вместо него.Почему не новый статус:
banned— сохранениеdone_buckets-чекпоинта — нужна обоим исходам; оставив статус, получаем её даром.Literal-фильтр admin API, хардкод-список статусов во фронте. Это ровно тот класс оборванной проводки, из-за которого задача и появилась.Чекпоинт
run_avito_full_loadпишет{**counters, "done_buckets": sorted(done)}вmark_banned— одинаково приban_kind='infra'иban_kind='platform'. Два теста стерегут оба исхода.Признак несётся от места порождения
Рантайм классифицирует по типу исключения, не по подстроке. Разбор текста есть только в миграции — разовая ретро-классификация 115 накопленных строк, помеченная как таковая.
Чего тут НЕТ
Возврат такта Авито — вынесен в #2687 на данные 9–10.08.
Test plan
tests/test_2686_ban_kind_split.py— 12 тестов: место порождения (sidecar → подтип, firewall → не подтип), перевод типа в диагноз, доставка диагноза доmark_banned+ сохранностьdone_bucketsу обоих исходов, записьban_kindв SQL обеими копиями runs-модуля.origin/mainфайл не импортируется (нет ни типа, ни хелпера); при точечном снятииban_kind=изrun_avito_full_loadпадаетtest_full_load_sidecar_ban_is_infra_and_keeps_checkpoint(platformвместоinfra).test_search_cache_hit, pre-existing order-dependent, deselect'ится в CI.deploy-tradein.yml(tradein-mvp/packages/scraper-kit/**) → правка доедет доtradein-scraper, который её исполняет.Refs #2686
Из 115 avito-прогонов со статусом 'banned' 92 (80%) — отказ НАШЕГО браузерного сайдкара («browser unavailable (proxy may be down)»), 10 — реальный firewall площадки, 11 — HTTP 429/403. Оба исхода писали разный текст ошибки и получали один статус: различитель лежал в данных и терялся в момент присвоения. По этому статусу миграция 206 замедлила avito_full_load_exhaustive более чем вдвое — основание было ложным. Разводим не пути, а диагноз: - AvitoSidecarUnavailableError — подтип AvitoRateLimitedError, поднимается ровно там, где отказ порождён нашей инфраструктурой. Подтип, а не отдельный класс, чтобы все `except (AvitoBlockedError, AvitoRateLimitedError)` продолжали ловить его без изменений — иначе прогон ушёл бы в mark_failed и потерял чекпоинт; - scrape_runs.ban_kind ('platform' | 'infra', миграция 218) рядом со status, а не вместо него. Новое значение статуса пришлось бы доучить пяти местам (CHECK, IN-списки обоих сторожей, Literal admin API, список статусов во фронте), каждое из которых молча врёт, если про него забыть; - побочная функция 'banned' — сохранение done_buckets-чекпоинта — остаётся у ОБОИХ исходов: следующий прогон не начинает с нуля ни при нашем отказе, ни при блокировке площадкой. Тест стережёт оба. Признак несётся от места порождения (тип исключения), а не разбирается из текста постфактум; разбор текста в миграции — разовая ретро-классификация истории. Возврат такта Авито сюда НЕ входит — он вынесен в #2687 на данные 9-10.08. Refs #2686ban_kindпроставляется по умолчанию у 9 вызывающих из 12 — метка выглядит доказательством, не будучи им #2764