fix(tradein): TTL-деактивация не исполняется, пока сбор по источнику лежит (#2659) #2710
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#2710
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/2659-ttl-knows-coverage"
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?
Что и почему
TTL-деактивация исполнялась вслепую. Авито 10.07-26.07.2026: 17 суток подряд без единой собранной страницы, TTL=10 снял за отрезок 9 033 строки (сумма
counters->>'deactivated'по прогонам, цифра из #2659 воспроизведена точно). 1 270 из них потом доказанно вернулись живыми — сверкаlisting_source_snapshots(кого TTL был обязан снять в те сутки) с текущимlast_seen_at. Задача прочитала «мы не смогли зайти» как «объявление снято».Почему не по статусу прогона
scrape_runs.status='banned'— ловушка, оба других провала для него невидимы:donedoneПоэтому здоровье меряется результатом: сколько строк источник подтвердил свежими за 3 суток — по той же колонке (
last_seen_at/scraped_at) и тому же срезуsource + segments, что и сам UPDATE. Одна колонка на обе стороны: гейт нельзя обмануть bulk-touch'ем, не двигающимscraped_at(#2204).Пороги (миграция 219)
Ряд «подтверждений за 3 суток» по дням восстановлен из
listing_source_snapshots:last_seen_at)scraped_at)Порог авито лежит строго между максимумом провала (970) и минимумом здоровых суток (3542). Цена ошибки асимметрична — пропущенная деактивация чинится следующим прогоном, ложная только повторным сбором, — поэтому пороги смещены в сторону «пропустить прогон».
domklik заблокируется сразу, и это верный исход: источник подтверждает ~50 строк в сутки, TTL по нему уже снёс инвентарь целиком 02.08. Протухшее там закрывается фильтром свежести на чтении (#2656), а не TTL.
Что НЕ трогается
Охват TTL не расширен ни на один сегмент — по порядку действий из #2659 (сначала #2656, потом TTL). Разбор новостроек Циана и несогласованности Яндекса — в комментарии к issue, отдельным PR после #2656.
Test plan
test_gate_blocks_every_day_of_the_17_day_avito_ban— проигрывает реальный прод-ряд подтверждений по дням: все 20 суток провала блокируются, ни одни здоровые сутки не задеты. Наorigin/mainпадает (12 из 21 теста файла падают на старом коде).deactivate_stale_domklikуходит вskipped_unhealthy=1, остальные три исполняются как раньшеRefs #2659
Авито 10.07-26.07.2026: 17 суток подряд без единой собранной страницы, TTL=10 снял за отрезок 9 033 строки. 1 270 из них потом вернулись живыми, как только сбор восстановился (сверка listing_source_snapshots с текущим last_seen_at) — задача прочитала «мы не смогли зайти» как «объявление снято». Гейт меряет здоровье НЕ статусом прогона, а результатом: сколько строк источник подтвердил свежими за 3 суток, по той же колонке (last_seen_at / scraped_at) и тому же срезу source+segment, что и сам UPDATE. Статус не годится — оба других провала для него невидимы: yandex 18.07-30.07 (13 суток, все прогоны 'done', ноль 'banned', total_seen=0) и domklik 20.07-30.07, чей TTL 02.08 снял 6 131 строку разом. Пороги посчитаны по ряду подтверждений из listing_source_snapshots и лежат между максимумом провала и минимумом здоровых суток: avito 1500 (провал 0..970, здоровье 3542..6079), yandex/cian 500, domklik 200. Миграция 219 кладёт их в default_params, не затирая ручную настройку; страховочный дефолт в коде — 500. Цена ошибки асимметрична (пропущенная деактивация чинится следующим прогоном, ложная — только повторным сбором), поэтому при сомнении прогон пропускается. Пропущенный прогон закрывается mark_done со счётчиками {deactivated: 0, confirmations: N, skipped_unhealthy: 1} — ни одна строка не тронута, статусы прогонов не менялись. Тест test_gate_blocks_every_day_of_the_17_day_avito_ban проигрывает реальный прод-ряд по дням: каждые сутки провала блокируются, здоровые — нет. Refs #2659