fix(trade-in): выключить домклик-свипы 77/50 — они по построению не могут ничего собрать
All checks were successful
CI Trade-In / changes (pull_request) Successful in 19s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 23s
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 5m23s

Замер 17.09 одиночным прогоном, без соседей по сайдкару и пулу. run 7344
(Москва, прокси 13, старт 06:12:48) за два часа прошёл 2 бакета из 6: 'st' —
34.2 мин, '1' — 86+ мин и не закончился. Watchdog прогона 11100 с.

Это не одновременность и не блок площадки: прогон был единственным, узел не
банился, QRATOR-блока в логе нет. Причина структурная. ДомКлик режет offset на
2000, поэтому на больших выдачах скрейпер делит диапазон по цене бисекцией, и
каждый лист пагинируется отдельно. У Москвы около 23 690 лотов вторички против
6 300 у ЕКБ — листьев кратно больше. Формула watchdog'а считает число фетчей как
6 * pages и объём выдачи не учитывает: 11100 = 600 * (6 + 12) + 300. Она линейна
по pages, так что уменьшение pages_per_anchor урезает и сам watchdog.

Хуже, чем «не успевает». _domclick_phase — единственная фаза fetch_city + save:
лоты копятся в памяти и сохраняются одним save_listings после всех шести
бакетов, снятие по watchdog теряет всё собранное. А чекпоинт #3118 пишется ПОСЛЕ
этого, из живой ссылки на скрейпер — бакеты помечаются пройденными, хотя ни одна
их строка не сохранена, и следующий прогон пропускает их через skip_buckets. Два-
три прогона закрывают чекпоинт целиком: итоговый сбор по 77/50 равен нулю
навсегда.

Пока строки включены, вред не нулевой: каждые трое суток каждая забирает один из
двух узлов affinity='any' на три часа впустую. 17.09 из-за этого ЕКБ-свип run
7339 отбился 'banned' за 0 секунд, пока оба узла держали московские прогоны.

Условия возврата перечислены в шапке миграции: инкрементальное сохранение по
бакетам, watchdog от объёма выдачи, кооперативная отмена по бакетам и сброс
унаследованного чекпоинта прогонов 7333/7344.

ЕКБ-строка не трогается — её выдача помещается в watchdog (run 7219: 70 минут,
6372 seen / 237 new).

Claude-Session: https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs
This commit is contained in:
bot-backend 2026-09-17 11:16:12 +03:00
parent 34642e1dd5
commit ad27ed3ab0

View file

@ -0,0 +1,60 @@
-- 308_domclick_msk_disable_until_incremental_save.sql
-- Выключить домклик-свипы 77/50: в текущем виде они по построению не могут ничего собрать.
--
-- Apply after: 307_domclick_msk_window_no_collision.sql
--
-- WHY (замерено 17.09.2026 одиночным прогоном, без соседей по сайдкару и пулу):
--
-- run 7344, source='domclick_city_sweep_moskva', прокси id=13, стартовал 06:12:48.
-- За ДВА часа пройдено 2 бакета из 6: 'st' занял 34.2 мин, '1' шёл 86+ мин и не
-- закончился. Watchdog прогона — 11100 с (3 ч 05 мин).
--
-- Это НЕ одновременность и НЕ блок площадки: прогон был единственным, узел не банился,
-- QRATOR-блока в логе нет. Причина структурная — ДомКлик режет offset на 2000, поэтому
-- на больших выдачах скрейпер бисекцией делит диапазон по цене на листья, и КАЖДЫЙ лист
-- пагинируется отдельно. У Москвы ≈23 690 лотов вторички против ≈6 300 у ЕКБ, листьев
-- кратно больше. А формула watchdog'а (pipeline.run_domclick_city_sweep) считает число
-- фетчей как _DOMCLICK_NUM_BUCKETS * pages = 6 * 100 и объём выдачи не учитывает вовсе:
-- 11100 = 600 * (6 + 12) + 300. Она линейна по pages, поэтому уменьшение
-- pages_per_anchor урезает и сам watchdog — лечения не даёт.
--
-- Хуже, чем просто «не успевает». _domclick_phase — «единственная citywide-фаза:
-- fetch_city + save»: лоты копятся в памяти и сохраняются ОДНИМ save_listings после
-- всех шести бакетов. Снятие фазы по watchdog (asyncio.wait_for → TimeoutError) теряет
-- всё собранное. При этом чекпоинт #3118 пишется ПОСЛЕ этого, из живой ссылки на
-- скрейпер: done_buckets = унаследованное _s.completed_buckets. То есть бакеты
-- помечаются пройденными, хотя ни одна их строка не сохранена, и следующий прогон
-- пропускает их через skip_buckets. Два-три таких прогона закрывают чекпоинт целиком —
-- итоговый сбор по 77/50 равен нулю навсегда.
--
-- Пока строки включены, вред не нулевой: каждые трое суток каждая забирает один из ДВУХ
-- узлов с provider_affinity='any' (id 13 и 14) на три часа и не отдаёт ничего. 17.09
-- из-за этого ЕКБ-свип run 7339 отбился 'banned' за 0 секунд, пока оба узла держали
-- московские прогоны. Выключение восстанавливает статус-кво ЕКБ.
--
-- ЧТО НУЖНО ДЛЯ ВОЗВРАТА (не в этой миграции — это правка кода в scraper-kit):
-- 1. Инкрементальное сохранение по бакетам: save_listings внутри цикла fetch_city
-- (колбэк on_bucket, как у run_cian_full_load), чтобы снятие по watchdog сохраняло
-- собранное, а чекпоинт перестал врать.
-- 2. Watchdog, зависящий от объёма выдачи (snippetsCount), а не только от pages.
-- 3. Кооперативная отмена по бакетам: runs.is_cancelled сейчас проверяется только ПЕРЕД
-- SERP-фазой, поэтому повисший свип нельзя снять до watchdog'а.
-- 4. При возврате — сбросить унаследованный чекпоинт (counters.done_buckets прогонов
-- 7333/7344), иначе resume пропустит бакеты 'st' и '1', по которым ничего не сохранено.
--
-- ЕКБ-строка 'domclick_city_sweep' НЕ трогается: её выдача помещается в watchdog
-- (run 7219 16.09 — 70 минут, 6372 seen / 237 new), у неё дефект не проявляется.
--
-- ИДЕМПОТЕНТНОСТЬ: UPDATE ... WHERE source IN (...) — повторный прогон переписывает то же
-- значение. Возврат — ручным UPDATE enabled = true после правок выше, либо новой
-- миграцией.
BEGIN;
SET LOCAL lock_timeout = '5s';
UPDATE scrape_schedules
SET enabled = false
WHERE source IN ('domclick_city_sweep_moskva', 'domclick_city_sweep_moskovskaya_oblast');
COMMIT;