fix(tradein/domclick): исчерпание пула прокси помечалось как отказ сбора (#3118) #3174
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3174
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/3118-domclick-no-proxy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Часть (б) из #3118: исчерпание пула прокси выглядело как отказ сбора площадкой.
Что было
NoProxyAvailableErrorподнимается изBrowserFetcher.__aenter__→_acquire_leaseдо первого HTTP-запроса. У соседей есть выделенная ветка (pipeline.py:3610,:3851,:4114), уrun_domclick_city_sweepеё не было — отказ проваливался в общийexcept Exception,_scraper_refоставался пустым, и логика честного статуса ниже видела «0 лотов и есть ошибки» →mark_failed("fetch errors — 0 listings"),ban_kind = NULL.Прод-след, прогон 5023 (27.08): умер за 51 мс,
errors_count = 1,ban_kind = NULL. Со стороны неотличимо от «Домклик нас забанил», хотя площадку даже не запрашивали — в пуле из четырёх узлов не осталось свободных (аренда держится на весь прогон, а в тот момент жили четыре прогона одновременно).Что стало
Отдельная ветка
except NoProxyAvailableErrorперед общимexcept Exception(порядок обязателен — это подклассException), внутри неёmark_banned(..., ban_kind=ban_kind_of_exception(exc))→BAN_KIND_INFRA. Отказ инфраструктуры теперь называется инфраструктурой.Ветку пришлось разместить во внутреннем блоке SERP-фазы: у домклика структура иная, чем у avito/cian/yandex — фаза обёрнута в
asyncio.wait_forсо своимtry/except, а не идёт прямымasync with Scraper()в основномtry.Заодно унаследованный чекпоинт (
done_buckets) сохраняется при таком отказе — иначе наш собственный сбой стирал бы прогресс возобновления.Проверка
Тест проверен на обратимость: без обработчика падает с
assert ['failed'] == ['banned']и логомmark_failed("fetch errors — 0 listings")— воспроизводит прод-баг один в один. С фиксом проходит,ban_kind == "infra". Смежные 88 domclick-тестов зелёные.Что НЕ входит
Часть (а) — метрика свежести по
status = 'done', из-за которой источник числился мёртвым, пока собирал данные — вынесена в #3172. Причина исчерпания пула (аренда на весь прогон + зомби-прогоны, держащие узлы часами) — отдельная тема, смежная с #2638 и #3171.Refs #3118, #2657
NoProxyAvailableError поднимается из BrowserFetcher.__aenter__ (_acquire_lease) ДО первого HTTP-запроса, когда пул прокси пуст — это НАША инфраструктура, не блокировка площадкой. У run_avito_full_load/run_cian_full_load/run_yandex_full_load уже есть выделенный except NoProxyAvailableError -> mark_banned(ban_kind='infra'), у run_domclick_city_sweep его не было: исключение проваливалось в общий except Exception внутри SERP-фазы, _scraper_ref оставался пустым, и честный статус ниже видел "0 лотов + errors>0" -> mark_failed("fetch errors — 0 listings") с ban_kind=NULL. Прод-факт: run 5023 (27.08) умер за 51 мс, errors_count=1, ban_kind=NULL — неотличимо от честного отказа сбора площадкой. Добавлен except NoProxyAvailableError перед generic except Exception (порядок важен: класс — подкласс RuntimeError). Обработчик зеркалит avito/cian/yandex: mark_banned + ban_kind_of_exception(exc) (даёт BAN_KIND_INFRA), и сохраняет унаследованный чекпоинт (skip_buckets) вместо потери его на нашем же отказе. Тест test_3118_domclick_no_proxy.py проверен на обратимость: без обработчика падает (mark_failed вместо mark_banned), с обработчиком — проходит.