fix(tradein/proxy): проба спрашивает каждую площадку, вердикт пишется на пару «узел × источник» (#2800 B) #2803

Merged
bot-backend merged 1 commit from fix/2800b-per-source-probe into main 2026-08-09 18:28:38 +00:00

1 commit

Author SHA1 Message Date
2e30fbe8e3 fix(tradein/proxy): проба спрашивает каждую площадку, вердикт пишется на пару «узел × источник» (#2800 B)
All checks were successful
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
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 Trade-In / backend-tests (pull_request) Successful in 3m53s
#2723 починил ТРАНСПОРТ пробы — ходить браузером, как ходит работа. Ходила она при
этом для всех узлов на один зашитый адрес, robots.txt Авито. Прокси-узел не
«жив/мёртв» вообще: замер на проде 09.08.2026 тем же трактом —

  узел | affinity | avito | ekb.cian.ru         | realty.ya.ru | bff-search-web.domclick.ru
  -----+----------+-------+---------------------+--------------+---------------------------
    1  | domclick | 200   | 200 «Ошибка — Циан» | 200          | 500 NS_ERROR_PROXY_BAD_GATEWAY
    9  | any      | 200   | 200                 | 200          | 200
   10  | any      | 200   | 200                 | 200          | 200
   11  | any      | 200   | 200                 | 200          | 200

— у узла 1 при этом browser_fail_streak=0 и свежая проба. Зелёный ответ означал
«годен для Авито», а читался как «годен».

Что сделано:

1. Адрес пробы на КАЖДЫЙ источник и по РАБОЧЕМУ хосту площадки. Apex не годится:
   через тот же узел domclick.ru отвечает 200, а bff-search-web.domclick.ru, куда
   ходит сбор, — 500. Проба по apex была бы зелёной и бесполезной.
2. HTTP 200 с непустым телом больше не значит «площадка ответила»: robots.txt всех
   четырёх рабочих хостов содержит «User-agent», страница-заглушка Циана (374 КБ,
   «Ошибка — Циан») — нет. Раньше такой ответ засчитывался как успех.
3. Вердикт пары пишется в СУЩЕСТВУЮЩУЮ scrape_proxy_source_bans (её уже читает
   acquire(source)) — новой сущности и миграции нет. Свои строки помечены
   reason='probe:browser'; успешная проба снимает ТОЛЬКО их. Бан, распознанный
   боевым сбором, проба не гасит: robots.txt площадка отдаёт и забаненному IP, и
   позволить дешёвому успеху стирать дорогой вердикт значило бы повторить #2723.
4. Узловой вердикт (browser_fail_streak/browser_unfit_since) сохранил смысл
   «браузерный тракт через узел не работает вообще»: считается по итогу ВСЕГО
   креста — хоть одна зелёная площадка → ok, все красные транспортом → провал узла.
   Отказ одной площадки узел глобально не пятнает.
5. Транспортный отказ пары подтверждается немедленным повтором (браузер уже поднят,
   секунды, только на отказах) — один флаки-запуск camoufox не стоит паре 6 часов.

Цена, посчитана до правки: было 4 узла × 1 адрес / 360 мин = 16 навигаций в сутки,
стало 4 × 4 = 64, то есть 16 robots.txt НА ПЛОЩАДКУ в сутки против ~1000 боевых
/fetch. Такт (BROWSER_PROBE_MINUTES=360) не изменён, прогонов с браузерной пробой
по-прежнему 4 в сутки; крест ограничен источниками, которым узел может достаться.
Разрежённая схема (по источнику за такт, round-robin) отвергнута: вердикт пары
протухал бы до 24 ч при бане в 6 ч — окно, в котором acquire снова выдаёт узел.

Два теста #2723 обновлены осознанно: они считали вызовы пробы за прогон (1 → 4),
семантика такта не менялась.

Refs #2800
2026-08-09 23:12:32 +05:00