feat(tradein/scraper): чекпоинт по якорям для cian_city_sweep (#3074) #3117
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#3117
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/3074-cian-anchor-checkpoint"
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?
Третий шард после yandex (#3098) и avito (#3112).
Почему именно этот источник
Замер за 60 дней:
Пятиминутного дренажа из #3029 на прогоны такой длительности не хватает: убитый на 35-й минуте сбор начинался заново с первого якоря. Свип живой и результативный — последний прогон собрал 1680 лотов, — поэтому терять его целиком особенно обидно.
Отличие от avito-шарда, и почему здесь проще
У avito успех и неудача якоря сходились в одной строке
counters.anchors_done = idx, и понадобился отдельный флаг_anchor_ok.У циана граница уже проведена самим потоком управления: все ветки отказа (
TimeoutError, genericException, баны) делаютreturnилиcontinueи до записи чекпоинта не доходят. Точка успеха — единственная, после всехexcept. Добавлять флаг значило бы дублировать то, что уже выражено структурой, поэтому чекпоинт пишется ровно там.Тест на этот инвариант всё равно есть — отдельный. Рефакторинг, сливающий ветки в одну, сломал бы границу незаметно: упавший якорь попал бы в чекпоинт, следующий прогон пропустил бы его навсегда, и прогон при этом завершался бы штатно. Часть города просто перестала бы собираться.
Решения
Ключ — имя якоря, а не индекс. Состав списка зависит от
city_slug: областные свипы (cian_city_sweep_nizhniy_tagil,_serov,_pervouralskи ещё четыре) идут по своим наборам, и позиция между городами не устойчива.Гарда по числу якорей не нужна — в отличие от combo-чекпоинта яндекса, где
combo_labelякоря не содержал и пропуск был бы пропуском чужих якорей. Здесь якорь и есть ключ.Пропущенный якорь двигает
anchors_done— чтобы счётчик продолжал означать «докуда дошли по списку», а не «сколько собрал именно этот прогон».Тесты
tradein-mvp/backend/tests/test_3074_cian_anchor_checkpoint.py, 4 поведенческих — с подменойCianScraperиsave_listings:Двойнику пришлось добавить счётчики
state_extraction_attempts/failures: конвейер читает их у скрапера после каждого якоря (#2625), и без них падал бы сам двойник, а не проверяемая логика — то есть тест «краснел» бы по причине, не имеющей отношения к делу.Фальсификация: на исходном коде краснеют все 4 (
TypeError: unexpected keyword argument 'resume_run_id'— как и в avito-шарде, это доказывает отсутствие параметра; поведенческую часть держат сами утверждения). Весь набор #3074 — 14 passed.ruffчист.Что остаётся в #3074
domclick_city_sweep. Утром я вынес его из плана по замеру отмен деплоем (54 прогона, ноль отмен, среднее 3 минуты) — и это решение стоит пересмотреть: по свежим данным сбор рвётся блоком QRATOR на середине, собрав 1815 объявлений 25.08 и 235 сегодня, а статус при этомbanned. Чекпоинт там окупился бы, если блок временный — это ещё не проверено.Refs #3074, #3098, #3112