fix(tradein/avito): бан-страница площадки уезжала в транспортные сбои и не банила узел (#3283) #3304

Merged
bot-backend merged 1 commit from fix/3283c-avito-sidecar-ban-is-platform-ban into main 2026-08-31 14:53:18 +00:00
Owner

Проблема

Сайдкар распознаёт бан-страницу Авито («доступ ограничен: проблема с IP») по маркерам тела и отдаёт 500 с ban_page=true; клиент поднимает SidecarBanPageError. У Домклика её разбирают (#3239/#3283), у Авито — нет: она попадала в общий except Exception и заворачивалась в AvitoSidecarUnavailableError, то есть в ban_kind='infra'.

Следствие — не ярлык, а неработающая защита: report_ban не вызывался, узел не попадал в scrape_proxy_source_bans и продолжал выдаваться в аренду для source=avito.

Замер на проде

Прогон 5606 (31.08, 16:14–16:37): 64 бан-страницы за 23 минуты, ban_kinds={"infra":26,"platform":7}, ноль записей бана для avito, прогон оборван по доле блоков 14/20. enriched=24 из 59 попыток.

Что сделано

  • providers/avito/detail.py — ветка except SidecarBanPageError перед общим except Exception. Порядок важен: это подкласс httpx.HTTPStatusError.
  • providers/avito/serp.py — та же проверка до ротации и transient-бюджета. Ротация в этой ветке мертва (max_rot=0), поэтому ретраи маркерного бана ушли бы на тот же забаненный адрес: ещё два захода на площадку и ~4-5 с задержки перед report_ban. Бюджет задуман под блипы сайдкара (503 browser unavailable), а не под отказ площадки.

Детект в сайдкаре маркерный и положительный, а не догадка по коду ответа, — переспрашивать его нечем.

Регрессии закрыты тестами

backend/tests/test_3283_avito_sidecar_ban_is_platform_ban.py — 5 тестов в обе стороны:

  • бан-страница у fetch_detailAvitoBlockedError + report_ban вызван;
  • бан-страница у _fetch_serp_html → то же, плюс fetch.await_count == 1 и sleep ни разу не ожидался (ретраев нет);
  • обычная 500/503 без ban_page → остаётся AvitoSidecarUnavailableError, report_ban не вызывается.

Проверка

5257 passed, 37 skipped — полный набор backend. ruff чисто.

Что НЕ входит

HTTP 439 и затирание exit_ip в proxy_pool — отдельные PR.

## Проблема Сайдкар распознаёт бан-страницу Авито («доступ ограничен: проблема с IP») по маркерам тела и отдаёт `500` с `ban_page=true`; клиент поднимает `SidecarBanPageError`. У Домклика её разбирают (#3239/#3283), **у Авито — нет**: она попадала в общий `except Exception` и заворачивалась в `AvitoSidecarUnavailableError`, то есть в `ban_kind='infra'`. Следствие — не ярлык, а неработающая защита: `report_ban` не вызывался, узел не попадал в `scrape_proxy_source_bans` и продолжал выдаваться в аренду для `source=avito`. ## Замер на проде Прогон **5606** (31.08, 16:14–16:37): 64 бан-страницы за 23 минуты, `ban_kinds={"infra":26,"platform":7}`, **ноль записей бана для avito**, прогон оборван по доле блоков 14/20. `enriched=24` из 59 попыток. ## Что сделано - `providers/avito/detail.py` — ветка `except SidecarBanPageError` **перед** общим `except Exception`. Порядок важен: это подкласс `httpx.HTTPStatusError`. - `providers/avito/serp.py` — та же проверка **до** ротации и transient-бюджета. Ротация в этой ветке мертва (`max_rot=0`), поэтому ретраи маркерного бана ушли бы на тот же забаненный адрес: ещё два захода на площадку и ~4-5 с задержки перед `report_ban`. Бюджет задуман под блипы сайдкара (`503 browser unavailable`), а не под отказ площадки. Детект в сайдкаре маркерный и положительный, а не догадка по коду ответа, — переспрашивать его нечем. ## Регрессии закрыты тестами `backend/tests/test_3283_avito_sidecar_ban_is_platform_ban.py` — 5 тестов в обе стороны: - бан-страница у `fetch_detail` → `AvitoBlockedError` + `report_ban` вызван; - бан-страница у `_fetch_serp_html` → то же, **плюс** `fetch.await_count == 1` и `sleep` ни разу не ожидался (ретраев нет); - обычная `500`/`503` без `ban_page` → остаётся `AvitoSidecarUnavailableError`, `report_ban` **не** вызывается. ## Проверка `5257 passed, 37 skipped` — полный набор backend. `ruff` чисто. ## Что НЕ входит HTTP 439 и затирание `exit_ip` в `proxy_pool` — отдельные PR.
lekss361 added 1 commit 2026-08-31 14:24:56 +00:00
fix(tradein/avito): бан-страница площадки уезжала в транспортные сбои и не банила узел (#3283)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 12s
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 4m52s
62980396db
Сайдкар распознаёт бан-страницу Авито («доступ ограничен: проблема с IP») по
маркерам тела и отдаёт 500 с ban_page=true; клиент поднимает
SidecarBanPageError. У Домклика её разбирают (#3239/#3283), у Авито — нет:
она попадала в общий `except Exception` и заворачивалась в
AvitoSidecarUnavailableError, то есть в ban_kind='infra'. Следствие — не
ярлык, а неработающая защита: report_ban не вызывался, узел не попадал в
scrape_proxy_source_bans и продолжал выдаваться в аренду для source=avito.

Прод, прогон 5606 (31.08): 64 бан-страницы за 23 минуты,
ban_kinds={"infra":26,"platform":7}, ноль записей бана для avito, прогон
оборван по доле блоков 14/20.

detail.py — ветка `except SidecarBanPageError` перед общим `except Exception`
(порядок важен: это подкласс httpx.HTTPStatusError). serp.py — та же проверка
ДО ротации и transient-бюджета: ротация в этой ветке мертва (max_rot=0),
поэтому ретраи маркерного бана ушли бы на тот же забаненный адрес — ещё два
захода на площадку и ~4-5 с задержки перед report_ban. Бюджет задуман под
блипы сайдкара (503 «browser unavailable»), а не под отказ площадки.

Обычная 500 без ban_page по-прежнему остаётся транспортным сбоем и report_ban
не вызывает — закреплено тестами в обе стороны.

Тесты: 5257 passed, 37 skipped.
bot-backend merged commit 72cb410b05 into main 2026-08-31 14:53:18 +00:00
bot-backend deleted branch fix/3283c-avito-sidecar-ban-is-platform-ban 2026-08-31 14:53:18 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3304
No description provided.