fix(tradein/imv): домовая оценка ходит в сайдкар через пул, а не через чужой env-прокси (#2698) #2708

Merged
bot-backend merged 1 commit from fix/2698-imv-outage into main 2026-08-06 06:52:16 +00:00
Collaborator

Что чинит

Домовая оценка Авито (house_imv_backfill) не сохранила ни одной записи с 03.07 — 34 дня, каждый прогон {"saved": 0, "errors": 35, "checked": 50}. Отказ приходил от нашего собственного сайдкара, при этом сайдкар был жив.

Корневая причина (с контрольной группой)

backfill_house_imvединственный avito-путь, который конструировал BrowserFetcher без proxy_provider/use_pool/environment (house_imv_backfill.py:581; сравнить с orchestration/pipeline.py:519). Без них тело POST /fetch-json уходит без поля proxy → сайдкар берёт свой SCRAPER_PROXY_URL → на проде это узел пула id=1 (asocks-residential-1, provider_affinity='domclick'), который proxy_pool.acquire('avito') не выдал бы никогда.

Контрольная группа в те же сутки, через тот же сайдкар и тот же инстанс камуфокса:

дата avito_city_sweep avito_newbuilding_sweep house_imv_backfill
01.08 78 seen / 69 new 484 / 447 0 saved / 35 errors
02.08 269 / 132 397 / 191 0 / 35
05.08 300 / 122 508 / 255 0 / 35

Разница ровно одна — поле proxy в теле запроса. Побочный эффект той же дыры: запрос без proxy роняет сайдкару желаемый прокси на env → _ensure_browser релончит камуфокс на каждый дом, сбивая тёплый браузер sweep'ам.

Механизм 500 подтверждён живым логом сайдкара (06.08 04:12, тот же env-прокси): Page.goto: NS_ERROR_PROXY_BAD_GATEWAYexcept Exception → HTTP 500.

Второй дефект: причина отказа выбрасывалась

Сайдкар кладёт причину в тело ({"error": "browser unavailable (proxy may be down)"}), а resp.raise_for_status() печатает только код — ровно эта строка 34 дня лежала в houses.imv_error_reason у 1240 домов. Общий _raise_for_sidecar_status (оба эндпоинта, /fetch и /fetch-json) добавляет тело в текст ошибки. Тип исключения прежний (HTTPStatusErrorHTTPError) → retry-политика не меняется.

Test plan

  • tests/test_2698_imv_sidecar_wiring.py — проводка пула доезжает до фетчера; причина сайдкара доезжает до вызывающего на обоих эндпоинтах
  • прежний parity-тест эндпоинта расширен новыми аргументами (не ослаблен)
  • полный прогон: 3555 passed, 1 deselected (известный pre-existing test_search_cache_hit)

Что НЕ чинится этим PR

403 от самой площадки (31 дом) и живость единственного исходящего IP — ротация пула ждёт ASOCKS_API_TOKEN (#2638, пункт 5 в #2704).

Часть «честность прогона» из #2698 уже на проде до этого PR — см. комментарий к issue.

Refs #2698

## Что чинит Домовая оценка Авито (`house_imv_backfill`) не сохранила ни одной записи с 03.07 — 34 дня, каждый прогон `{"saved": 0, "errors": 35, "checked": 50}`. Отказ приходил от нашего собственного сайдкара, при этом сайдкар был жив. ## Корневая причина (с контрольной группой) `backfill_house_imv` — **единственный** avito-путь, который конструировал `BrowserFetcher` без `proxy_provider`/`use_pool`/`environment` (`house_imv_backfill.py:581`; сравнить с `orchestration/pipeline.py:519`). Без них тело `POST /fetch-json` уходит без поля `proxy` → сайдкар берёт свой `SCRAPER_PROXY_URL` → на проде это узел пула `id=1` (`asocks-residential-1`, `provider_affinity='domclick'`), который `proxy_pool.acquire('avito')` не выдал бы никогда. Контрольная группа в те же сутки, через тот же сайдкар и тот же инстанс камуфокса: | дата | avito_city_sweep | avito_newbuilding_sweep | house_imv_backfill | |---|---|---|---| | 01.08 | 78 seen / 69 new | 484 / 447 | 0 saved / 35 errors | | 02.08 | 269 / 132 | 397 / 191 | 0 / 35 | | 05.08 | 300 / 122 | 508 / 255 | 0 / 35 | Разница ровно одна — поле `proxy` в теле запроса. Побочный эффект той же дыры: запрос без `proxy` роняет сайдкару желаемый прокси на env → `_ensure_browser` релончит камуфокс на каждый дом, сбивая тёплый браузер sweep'ам. Механизм 500 подтверждён живым логом сайдкара (06.08 04:12, тот же env-прокси): `Page.goto: NS_ERROR_PROXY_BAD_GATEWAY` → `except Exception` → HTTP 500. ## Второй дефект: причина отказа выбрасывалась Сайдкар кладёт причину в тело (`{"error": "browser unavailable (proxy may be down)"}`), а `resp.raise_for_status()` печатает только код — ровно эта строка 34 дня лежала в `houses.imv_error_reason` у 1240 домов. Общий `_raise_for_sidecar_status` (оба эндпоинта, `/fetch` и `/fetch-json`) добавляет тело в текст ошибки. Тип исключения прежний (`HTTPStatusError` ⊂ `HTTPError`) → retry-политика не меняется. ## Test plan - [x] `tests/test_2698_imv_sidecar_wiring.py` — проводка пула доезжает до фетчера; причина сайдкара доезжает до вызывающего на обоих эндпоинтах - [x] прежний parity-тест эндпоинта расширен новыми аргументами (не ослаблен) - [x] полный прогон: 3555 passed, 1 deselected (известный pre-existing `test_search_cache_hit`) ## Что НЕ чинится этим PR 403 от самой площадки (31 дом) и живость единственного исходящего IP — ротация пула ждёт `ASOCKS_API_TOKEN` (#2638, пункт 5 в #2704). Часть «честность прогона» из #2698 уже на проде до этого PR — см. комментарий к issue. Refs #2698
bot-backend added 1 commit 2026-08-06 06:48:22 +00:00
fix(tradein/imv): домовая оценка ходит в сайдкар через пул, а не через чужой env-прокси (#2698)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (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 3m10s
aef43df650
Домовая оценка Авито не сохранила ни одной записи с 03.07 — 34 дня, каждый
прогон 35 отказов из 35 попыток. Отказ приходил от НАШЕГО сайдкара
(tradein-browser:3000/fetch-json): 1240 домов «503 Service Unavailable»
(до 02.08), затем 83 «500 Internal Server Error» и 31 «403 auth rejected»
(05.08). При этом сам сайдкар был жив.

1. Проводка пула. backfill_house_imv конструировал
   BrowserFetcher(source="avito", endpoint=...) без proxy_provider/use_pool/
   environment — единственный avito-путь без пула (avito_city_sweep его
   подключает, orchestration/pipeline.py:519). Без них тело POST /fetch-json
   уходит БЕЗ "proxy", и сайдкар берёт свой env-прокси SCRAPER_PROXY_URL. На
   проде это узел пула id=1 (asocks-residential-1, provider_affinity='domclick')
   — узел, который proxy_pool.acquire('avito') не выдал бы никогда: он отбирает
   affinity IN (provider,'any'), а последний узел выделенной affinity ещё и
   защищён от fallback (173_scrape_proxies_add_domclick_affinity.sql).

   Контрольная группа в тех же сутках: avito_city_sweep и
   avito_newbuilding_sweep тянули сотни объявлений через ТОТ ЖЕ сайдкар и тот
   же инстанс камуфокса (01.08: 78/69 и 484/447), пока house_imv_backfill
   получал 35 отказов из 35. Разница ровно одна — поле "proxy" в теле запроса.
   Второй эффект этой же дыры: запрос без "proxy" роняет сайдкару желаемый
   прокси на env → relaunch камуфокса на каждый дом (server.py::_ensure_browser),
   то есть путь IMV ещё и сбивал тёплый браузер sweep'ам.

   environment пробрасывается ради #2616 шаг 1: иначе прод-отказ «пул пуст»
   на этом пути мёртв и фетчер молча уходит на тот самый env-прокси.

2. Причина отказа больше не выбрасывается. Сайдкар кладёт её в тело
   ({"error": "browser unavailable (proxy may be down)"} / {"error": "Error:
   Page.goto: NS_ERROR_PROXY_BAD_GATEWAY"}), а resp.raise_for_status() печатает
   только код: ровно строка «Server error '503 Service Unavailable' for url
   'http://tradein-browser:3000/fetch-json'» и лежала 34 дня в
   houses.imv_error_reason у 1240 домов. Общий _raise_for_sidecar_status в
   browser_fetcher (оба вызова, /fetch и /fetch-json) добавляет тело в текст
   ошибки; тип исключения прежний (HTTPStatusError ⊂ HTTPError), retry-политика
   не меняется.

Тесты: проводка пула доезжает до фетчера; причина сайдкара доезжает до
вызывающего на обоих эндпоинтах. Прежний parity-тест эндпоинта расширен
новыми аргументами (не ослаблен).

Не чинится кодом (в #2704): 403 от самой площадки и живость единственного
исходящего IP — ротация пула ждёт ASOCKS_API_TOKEN (#2638).

Refs #2698
bot-backend merged commit c66e18cd13 into main 2026-08-06 06:52:16 +00:00
bot-backend deleted branch fix/2698-imv-outage 2026-08-06 06:52:17 +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#2708
No description provided.