fix(tradein/domclick): свип ходит через прокси-пул, а отказ узла не обнуляет прогон (#2657) #2796

Merged
bot-backend merged 1 commit from fix/2657-domclick-proxy-pool into main 2026-08-09 17:21:50 +00:00
Collaborator

Что нашлось

Постановка #2657 (от 05.08: «свип даёт ~1% предложения») на сегодня устарела в худшую сторону: с 06.08 свип даёт 0, а не 1%.

Прод 09.08:

дата domclick_city_sweep cian yandex avito
09.08 0 (failed, buckets 0/6) 1680 1952 120
08.08 0 1680 2744 159
07.08 0 1680 2669 134
06.08 0 1680 1239 131
05.08 59 1540 2643 300

Контрольная группа отвечает: упал ОДИН Домклик, инфраструктура ни при чём.

listings.source='domklik': 376 активных, max(scraped_at) = 2026-08-05 05:43 — четверо суток без единого подтверждения.

Где теряется

НЕ QRATOR и НЕ куки. Логи прогона 3502 (09.08 03:52):

BrowserFetcher: клиент создан, endpoint=http://tradein-browser:3000 proxy_lease_id=None
httpx.HTTPStatusError: 500 ... | tradein-browser: {"error": "Page.goto: NS_ERROR_PROXY_BAD_GATEWAY"}
domclick-sweep run_id=3502 done: lots=0 buckets=0/6 errors=1 blocked=0

proxy_lease_id=None — домклик единственный из sweep-источников не подключён к пулу (#2160 P4). Значит сайдкар идёт через статический SCRAPER_PROXY_URL = scrape_proxies.id=1 (residential, provider_affinity='domclick', миграция 173).

Живая проба тем же трактом (прод-сайдкар, 09.08), один и тот же URL BFF:

узел результат
id=1 residential (affinity=domclick) 500 NS_ERROR_PROXY_BAD_GATEWAY
id=10 mobile (пул, affinity=any) 200, {"offersCount":704,"snippetsCount":678}

Второй дефект рядом: fetch_city ловил только ValueError/TypeError (ошибки разбора). httpx.HTTPStatusError от сайдкара летел мимо цикла по ROOM_BUCKETS и убивал прогон на ПЕРВОМ бакете — отсюда buckets=0/6. Он же не давал сработать ротации lease после N подряд провалов (_LEASE_ROTATE_AFTER_FAILS): до неё не доживали.

Правка

  1. _job_domclick_city_sweepproxy_provider=ctx.proxy_provider (как у всех остальных свипов); проброс через run_domclick_city_sweepDomClickScraperbuild_browser_fetcher.
  2. Бакет-уровневый except расширен до Exception (не BaseExceptionCancelledError обязан проходить насквозь): отказ одного бакета не обнуляет прогон, битый бакет по-прежнему НЕ засчитывается в охват (#2670), статус остаётся честным.

Побочно: fetcher.report_ban при QRATOR-блоке перестаёт быть пустышкой — с пулом узел уходит в scrape_proxy_source_bans.

Опровергнутые предпосылки

  • «Охват ~1%» — на сегодня 0%, не 1%.
  • «Теряется на блоке QRATOR» (#2657 body) — с 06.08 блока в прогонах нет вовсе (blocked=0), отказ транспортный.
  • «Протухшие куки Домклика» (#2704 п.5) — к свипу отношения не имеют: свип кук не шлёт, а BFF через рабочий узел отдаёт данные без всякой сессии.
  • «QRATOR банит все прокси кроме одного чистого residential» (миграция 173 / #2000) — мобильный узел пула домкликовский BFF пускает; residential как раз не пускает.

Test plan

  • 3 новых теста красные на старом коде (TypeError: unexpected keyword argument 'proxy_provider'; HTTPStatusError наружу), зелёные на новом
  • pytest -k "domclick or proxy or scheduler or pipeline or browser" — 435 passed
  • ruff check + format
  • Прод-верификация, критерий записан ДО факта: первый прогон domclick_city_sweep после деплоя даёт lots_fetched > 1000 и buckets_completed >= 5. Проверять запросом:
    select id, started_at, status, counters from scrape_runs where source='domclick_city_sweep' order by id desc limit 3;
    Если снова 0 при proxy_lease_id != None в логах — значит блок реально выше по потоку, и вопрос уходит владельцу (пополнение пула, #2638).

Не сделано здесь (нужен владелец / database-expert)

  • scrape_proxies.id=1: provider_affinity='domclick' теперь вредит — резервирует под Домклик узел, который для Домклика мёртв, и прячет его от остальных. Просится UPDATE ... SET provider_affinity='any' (или enabled=false) отдельной миграцией. Без неё код тоже выживает: узел выдаётся, падает, lease ротируется, consecutive_fails со временем его отключает — но первый бакет каждого прогона будет тратиться впустую.
  • Браузерная проба узла (#2723) ходит на https://www.avito.ru/robots.txt для ВСЕХ узлов. Поэтому id=1 стоит с browser_fail_streak=0 и свежим browser_check_at, будучи мёртвым для Домклика: проба идёт не тем трактом, что работа. Отдельный issue.
  • П.2 исходного issue (scripts/ingest_domclick_jsonl.py без run_id) не трогал.

Refs #2657

## Что нашлось Постановка #2657 (от 05.08: «свип даёт ~1% предложения») на сегодня **устарела в худшую сторону**: с 06.08 свип даёт **0**, а не 1%. Прод 09.08: | дата | domclick_city_sweep | cian | yandex | avito | |---|---|---|---|---| | 09.08 | **0** (failed, buckets 0/6) | 1680 | 1952 | 120 | | 08.08 | **0** | 1680 | 2744 | 159 | | 07.08 | **0** | 1680 | 2669 | 134 | | 06.08 | **0** | 1680 | 1239 | 131 | | 05.08 | 59 | 1540 | 2643 | 300 | Контрольная группа отвечает: упал ОДИН Домклик, инфраструктура ни при чём. `listings.source='domklik'`: 376 активных, `max(scraped_at) = 2026-08-05 05:43` — четверо суток без единого подтверждения. ## Где теряется НЕ QRATOR и НЕ куки. Логи прогона 3502 (09.08 03:52): ``` BrowserFetcher: клиент создан, endpoint=http://tradein-browser:3000 proxy_lease_id=None httpx.HTTPStatusError: 500 ... | tradein-browser: {"error": "Page.goto: NS_ERROR_PROXY_BAD_GATEWAY"} domclick-sweep run_id=3502 done: lots=0 buckets=0/6 errors=1 blocked=0 ``` `proxy_lease_id=None` — домклик единственный из sweep-источников не подключён к пулу (#2160 P4). Значит сайдкар идёт через статический `SCRAPER_PROXY_URL` = `scrape_proxies.id=1` (residential, `provider_affinity='domclick'`, миграция 173). **Живая проба тем же трактом (прод-сайдкар, 09.08), один и тот же URL BFF:** | узел | результат | |---|---| | id=1 residential (affinity=domclick) | 500 `NS_ERROR_PROXY_BAD_GATEWAY` | | id=10 mobile (пул, affinity=any) | **200**, `{"offersCount":704,"snippetsCount":678}` | Второй дефект рядом: `fetch_city` ловил только `ValueError/TypeError` (ошибки разбора). `httpx.HTTPStatusError` от сайдкара летел мимо цикла по `ROOM_BUCKETS` и убивал прогон на ПЕРВОМ бакете — отсюда `buckets=0/6`. Он же не давал сработать ротации lease после N подряд провалов (`_LEASE_ROTATE_AFTER_FAILS`): до неё не доживали. ## Правка 1. `_job_domclick_city_sweep` → `proxy_provider=ctx.proxy_provider` (как у всех остальных свипов); проброс через `run_domclick_city_sweep` → `DomClickScraper` → `build_browser_fetcher`. 2. Бакет-уровневый `except` расширен до `Exception` (не `BaseException` — `CancelledError` обязан проходить насквозь): отказ одного бакета не обнуляет прогон, битый бакет по-прежнему НЕ засчитывается в охват (#2670), статус остаётся честным. Побочно: `fetcher.report_ban` при QRATOR-блоке перестаёт быть пустышкой — с пулом узел уходит в `scrape_proxy_source_bans`. ## Опровергнутые предпосылки - «Охват ~1%» — на сегодня 0%, не 1%. - «Теряется на блоке QRATOR» (#2657 body) — с 06.08 блока в прогонах нет вовсе (`blocked=0`), отказ транспортный. - «Протухшие куки Домклика» (#2704 п.5) — к свипу отношения не имеют: свип кук не шлёт, а BFF через рабочий узел отдаёт данные без всякой сессии. - «QRATOR банит все прокси кроме одного чистого residential» (миграция 173 / #2000) — мобильный узел пула домкликовский BFF пускает; residential как раз не пускает. ## Test plan - [x] 3 новых теста красные на старом коде (`TypeError: unexpected keyword argument 'proxy_provider'`; `HTTPStatusError` наружу), зелёные на новом - [x] `pytest -k "domclick or proxy or scheduler or pipeline or browser"` — 435 passed - [x] ruff check + format - [ ] **Прод-верификация, критерий записан ДО факта:** первый прогон `domclick_city_sweep` после деплоя даёт `lots_fetched > 1000` и `buckets_completed >= 5`. Проверять запросом: `select id, started_at, status, counters from scrape_runs where source='domclick_city_sweep' order by id desc limit 3;` Если снова 0 при `proxy_lease_id != None` в логах — значит блок реально выше по потоку, и вопрос уходит владельцу (пополнение пула, #2638). ## Не сделано здесь (нужен владелец / database-expert) - `scrape_proxies.id=1`: `provider_affinity='domclick'` теперь вредит — резервирует под Домклик узел, который для Домклика мёртв, и прячет его от остальных. Просится `UPDATE ... SET provider_affinity='any'` (или `enabled=false`) отдельной миграцией. Без неё код тоже выживает: узел выдаётся, падает, lease ротируется, `consecutive_fails` со временем его отключает — но первый бакет каждого прогона будет тратиться впустую. - Браузерная проба узла (#2723) ходит на `https://www.avito.ru/robots.txt` для ВСЕХ узлов. Поэтому id=1 стоит с `browser_fail_streak=0` и свежим `browser_check_at`, будучи мёртвым для Домклика: проба идёт не тем трактом, что работа. Отдельный issue. - П.2 исходного issue (`scripts/ingest_domclick_jsonl.py` без `run_id`) не трогал. Refs #2657
bot-backend added 1 commit 2026-08-09 17:09:45 +00:00
fix(tradein/domclick): свип ходит через прокси-пул, а отказ узла не обнуляет прогон (#2657)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
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 3m54s
6d051d17af
Прод 06-09.08: domclick_city_sweep четыре прогона подряд `failed` с buckets=0/6,
lots=0. Не QRATOR и не куки — два сложившихся дефекта:

1. Домклик был ЕДИНСТВЕННЫМ sweep-источником без proxy_provider (#2160 P4):
   _job_domclick_city_sweep не передавал ctx.proxy_provider, поэтому
   build_browser_fetcher строил фетчер без пула и сайдкар шёл через статический
   SCRAPER_PROXY_URL. Этот адрес (scrape_proxies.id=1, residential,
   provider_affinity='domclick') отдаёт NS_ERROR_PROXY_BAD_GATEWAY именно на
   bff-search-web.domclick.ru. Живая проверка 09.08 через прод-сайдкар: тот же
   URL через id=1 → 500, через мобильный узел пула id=10 → 200 и
   snippetsCount=678 в бакете 'st'. Предпосылка миграции 173 («QRATOR банит все
   узлы кроме этого residential») опровергнута.

2. Транспортная ошибка убивала весь свип на первом бакете: fetch_city ловил
   только ValueError/TypeError (ошибки разбора), httpx.HTTPStatusError от
   сайдкара пролетал наружу мимо цикла по ROOM_BUCKETS. Это же не давало
   сработать ротации lease после N подряд провалов — до неё не доживали.

Побочно: fetcher.report_ban при QRATOR-блоке перестаёт быть пустышкой — с
подключённым пулом узел уходит в scrape_proxy_source_bans.

Фальсификация: 3 новых теста красные на старом коде (TypeError на
proxy_provider, HTTPStatusError наружу).

Refs #2657
bot-backend merged commit 7b36f86ea6 into main 2026-08-09 17:21:50 +00:00
bot-backend deleted branch fix/2657-domclick-proxy-pool 2026-08-09 17:21:50 +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#2796
No description provided.