fix(scraper-kit/cian): фаза houses cian_city_sweep через пул прокси + стоп на пустом пуле (#3394) #3396

Merged
bot-backend merged 2 commits from fix/3394-cian-sweep-houses-proxy-pool into main 2026-09-06 05:53:38 +00:00
Collaborator

Closes #3394.

Дефект. run_cian_city_sweep, фаза houses (orchestration/pipeline.py:3224): await fetch_newbuilding(zhk_url, config=config) без proxy_provider → в providers/cian/newbuilding.py фетчер без пула → /fetch без proxy → сайдкар на env-фолбэке SCRAPER_PROXY_URL (выключенный узел 9, 407) → camoufox InvalidIP → 503. Фаза работала 30/30 до 01.09 и падает целиком с 02.09 (смерть узла 9): run 6179 — 30/30 отказов, 24× Server error '503' for url 'http://tradein-browser:3000/fetch', в сайдкаре ни одной строки [cian] … override=True; за 04–06.09 Loki насчитал 4684 «503 браузер недоступен» по cian.

Фикс (pipeline.py): proxy_provider=proxy_provider в вызов (:3222-3234; тот же объект, что уже уходит в CianScraper и cian_fetch_detail); CianCitySweepCounters.no_proxy_stop: int (:2849, 1 — как у соседей); в houses-цикле if caused_by_no_proxy(exc): raise (:3243-3260, лог houses СТОП — пул прокси пуст); ветка except NoProxyAvailableError вокруг фаз якоря (:3336-3361, до generic) → no_proxy_stop=1, heartbeat + mark_banned(ban_kind=infra) с done_buckets — иначе наш отказ инфраструктуры копил consecutive_failures и через 3 якоря превращался в «IP likely blocked».

Аудит вызовов: cian_history_backfill.py:352 (RealProxyProvider, #3382), newbuilding_enrich_backfill.py:497/546, admin.py:2175 (_kit_proxy_provider()) — провайдер передают; дыра была только в свипе. fetch_newbuilding/resolve_cian_zhk_url_via_search NoProxyAvailableError наружу пропускают (глотания, как у yandex в #3389, нет).

Тесты tests/test_3394_cian_sweep_houses_proxy_pool.py: через настоящий run_cian_city_sweep → fetch_newbuilding → build_browser_fetcher, подделан только providers._base.BrowserFetcher: фетчер строится с proxy_provider is provider; пустой пул → ровно один дом, no_proxy_stop=1.

Фальсификация (git apply -R pipeline.py): assert None is <MagicMock proxy_provider> и второй дом упрётся в то же самое: Left contains 2 more items (три houses failed подряд в логе). Восстановлено.

Прогоны: полный backend 5532 passed, 35 skipped (rc=0); ruff OK.

Приёмка на проде: следующий cian_city_sweep (~03:30 UTC 07.09) — houses_enriched > 0 при houses_attempted > 0, в сайдкаре [cian] … override=True по newbuilding-страницам (с 02.09 не было ни одной), InvalidIP для cian = 0; при реально пустом пуле — ровно один houses failed, houses СТОП — пул прокси пуст, banned + no_proxy_stop=1.

Closes #3394. **Дефект.** `run_cian_city_sweep`, фаза houses (`orchestration/pipeline.py:3224`): `await fetch_newbuilding(zhk_url, config=config)` без `proxy_provider` → в `providers/cian/newbuilding.py` фетчер без пула → `/fetch` без `proxy` → сайдкар на env-фолбэке `SCRAPER_PROXY_URL` (выключенный узел 9, 407) → camoufox `InvalidIP` → 503. Фаза работала 30/30 до 01.09 и падает целиком с 02.09 (смерть узла 9): run 6179 — 30/30 отказов, 24× `Server error '503' for url 'http://tradein-browser:3000/fetch'`, в сайдкаре ни одной строки `[cian] … override=True`; за 04–06.09 Loki насчитал 4684 «503 браузер недоступен» по cian. **Фикс** (`pipeline.py`): `proxy_provider=proxy_provider` в вызов (`:3222-3234`; тот же объект, что уже уходит в `CianScraper` и `cian_fetch_detail`); `CianCitySweepCounters.no_proxy_stop: int` (`:2849`, `1` — как у соседей); в houses-цикле `if caused_by_no_proxy(exc): raise` (`:3243-3260`, лог `houses СТОП — пул прокси пуст`); ветка `except NoProxyAvailableError` вокруг фаз якоря (`:3336-3361`, до generic) → `no_proxy_stop=1`, heartbeat + `mark_banned(ban_kind=infra)` с `done_buckets` — иначе наш отказ инфраструктуры копил `consecutive_failures` и через 3 якоря превращался в «IP likely blocked». **Аудит вызовов:** `cian_history_backfill.py:352` (RealProxyProvider, #3382), `newbuilding_enrich_backfill.py:497/546`, `admin.py:2175` (`_kit_proxy_provider()`) — провайдер передают; дыра была только в свипе. `fetch_newbuilding`/`resolve_cian_zhk_url_via_search` `NoProxyAvailableError` наружу пропускают (глотания, как у yandex в #3389, нет). **Тесты** `tests/test_3394_cian_sweep_houses_proxy_pool.py`: через настоящий `run_cian_city_sweep → fetch_newbuilding → build_browser_fetcher`, подделан только `providers._base.BrowserFetcher`: фетчер строится с `proxy_provider is provider`; пустой пул → ровно один дом, `no_proxy_stop=1`. **Фальсификация** (`git apply -R` pipeline.py): `assert None is <MagicMock proxy_provider>` и `второй дом упрётся в то же самое: Left contains 2 more items` (три `houses failed` подряд в логе). Восстановлено. **Прогоны:** полный backend `5532 passed, 35 skipped` (rc=0); ruff OK. **Приёмка на проде:** следующий `cian_city_sweep` (~03:30 UTC 07.09) — `houses_enriched > 0` при `houses_attempted > 0`, в сайдкаре `[cian] … override=True` по newbuilding-страницам (с 02.09 не было ни одной), `InvalidIP` для cian = 0; при реально пустом пуле — ровно один `houses failed`, `houses СТОП — пул прокси пуст`, `banned` + `no_proxy_stop=1`.
bot-backend added 1 commit 2026-09-06 04:47:15 +00:00
fix(tradein/cian): houses-фаза cian_city_sweep идёт через пул прокси + стоп на пустом пуле (#3394)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 4m59s
e12ece8fe6
`run_cian_city_sweep` звал `fetch_newbuilding(zhk_url, config=config)` без
`proxy_provider`, хотя провайдер лежит в аргументах самого свипа и соседние
фазы (SERP через CianScraper, detail через cian_fetch_detail) его передают.
Внутри это давало `build_browser_fetcher(config, "cian", proxy_provider=None)`
→ `use_pool` эффективно False → POST /fetch без "proxy" → сайдкар брал свой
env-узел SCRAPER_PROXY_URL, на проде выключенный (407 → camoufox InvalidIP →
/fetch 503, факт #3386). Фаза houses давала 0/30 с 02.09 (run 6179: 24 ×
`houses failed ... 503 Service Unavailable`), строк `override=True` в логах
сайдкара по ней не было ни одной. Остальные вызывающие `fetch_newbuilding` /
`resolve_cian_zhk_url_via_search` провайдер уже передают (#2767/#2830/#3382),
этот вызов был последним мимо пула.

Второе: пустой пул поднимается ДО запроса, следующий дом упрётся ровно в то
же самое — общий `except Exception` на дом превращал это в 30 одинаковых
houses_failed и прогон уходил в 'done'. Теперь NoProxyAvailableError рвёт
фазу и свип: `no_proxy_stop=1` в counters, mark_banned с ban_kind='infra' и
сохранённым done_buckets (образец — #3389 yandex-nb-sweep, #3382). Ветка
стоит ДО generic-except, иначе наш отказ инфраструктуры читался бы как
«IP likely blocked» — бан площадки.
Author
Collaborator

Code-review (06.09): minor, блокеров нет. Подтверждено: порядок except (TimeoutError → NoProxyAvailableError → generic; логика «IP likely blocked» только в timeout/generic); mark_banned(ban_kind=infra) — локальный прецедент в этом же файле (cian full-load :3788, avito :4071/:4342, :4632), стрик failed/banned не различает статусы; done_buckets доезжают через mark_banned, banned_RESUME_STATUSES; no_proxy_stop уезжает 1; тесты через настоящий run_cian_city_sweep → fetch_newbuilding → build_browser_fetcher.

Докатываю до мержа: (1) raise-site решает по цепочке причин, а catch-site на уровне якоря ловит только голый NoProxyAvailableError — как только fetch_newbuilding начнёт оборачивать исключение (как fetch_detail), стоп уйдёт в generic → «IP likely blocked» без no_proxy_stop; ловлю по caused_by_no_proxy на уровне якоря + тест с обёрнутым исключением; (2) errors_count дважды на одно событие; (3) комментарий про «лоте» — detail-фаза глотает; (4) ассерты use_pool/environment не различают эпохи, ban_kind='infra' без покрытия — исправляю.

Code-review (06.09): minor, блокеров нет. Подтверждено: порядок `except` (TimeoutError → NoProxyAvailableError → generic; логика «IP likely blocked» только в timeout/generic); `mark_banned(ban_kind=infra)` — локальный прецедент в этом же файле (cian full-load `:3788`, avito `:4071/:4342`, `:4632`), стрик failed/banned не различает статусы; `done_buckets` доезжают через `mark_banned`, `banned` ∈ `_RESUME_STATUSES`; `no_proxy_stop` уезжает `1`; тесты через настоящий `run_cian_city_sweep → fetch_newbuilding → build_browser_fetcher`. Докатываю до мержа: (1) raise-site решает по цепочке причин, а catch-site на уровне якоря ловит только голый `NoProxyAvailableError` — как только `fetch_newbuilding` начнёт оборачивать исключение (как `fetch_detail`), стоп уйдёт в generic → «IP likely blocked» без `no_proxy_stop`; ловлю по `caused_by_no_proxy` на уровне якоря + тест с обёрнутым исключением; (2) `errors_count` дважды на одно событие; (3) комментарий про «лоте» — detail-фаза глотает; (4) ассерты `use_pool/environment` не различают эпохи, `ban_kind='infra'` без покрытия — исправляю.
Light1YT added 1 commit 2026-09-06 05:16:25 +00:00
fix(#3394): стоп по пустому пулу — по цепочке причин на уровне якоря; один errors_count; ban_kind=infra под тестом
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
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 4m55s
fdae823762
bot-backend merged commit e1f86e3c1b into main 2026-09-06 05:53:38 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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#3396
No description provided.