All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 2m56s
Deploy Trade-In / build-backend (push) Successful in 1m1s
Deploy Trade-In / deploy (push) Successful in 1m16s
67 lines
4.9 KiB
PL/PgSQL
67 lines
4.9 KiB
PL/PgSQL
-- 219_deactivate_stale_health_gate.sql
|
||
-- Пороги гейта здоровья сбора для TTL-деактивации (#2659).
|
||
--
|
||
-- ЗАЧЕМ. TTL отвечает на вопрос «объявление сняли?», а меряет «мы его давно не
|
||
-- видели». Пока обход здоров, разница мала; когда обход лёг — разница равна всему
|
||
-- инвентарю. Прод, авито 10.07-26.07.2026: 17 суток подряд без единой собранной
|
||
-- страницы, TTL=10 снял 9 033 строки, из них 1 270 доказанно вернулись живыми,
|
||
-- как только сбор восстановился (сверка listing_source_snapshots с текущим
|
||
-- last_seen_at). Код гейта — app/tasks/deactivate_stale_avito.py.
|
||
--
|
||
-- ПОЧЕМУ НЕ ПО СТАТУСУ ПРОГОНА. Ban-детектор эти провалы НЕ ловит:
|
||
-- yandex 18.07-30.07 — 5 прогонов в сутки, ВСЕ 'done', НОЛЬ 'banned',
|
||
-- total_seen = 0 тринадцать суток подряд;
|
||
-- domklik 20.07-30.07 — 11 суток 'done' с total_seen = 0, а 02.08 TTL=14
|
||
-- снял 6 131 строку разом.
|
||
-- Поэтому здоровье меряется результатом (сколько строк источник реально подтвердил
|
||
-- свежими за 3 суток), а не статусом прогона.
|
||
--
|
||
-- ОТКУДА ЧИСЛА. Ряд «подтверждений за 3 суток» по дням восстановлен из
|
||
-- listing_source_snapshots (снимок last_seen_at на каждую дату), срез совпадает
|
||
-- со срезом соответствующего UPDATE (source + segments + та же колонка свежести):
|
||
-- avito (все сегменты, last_seen_at): здоровые сутки 3542..6079,
|
||
-- провал 08.07-29.07 — 0..970 -> 1500
|
||
-- yandex (vtorichka, last_seen_at): здоровые 897..2206, провал 0 -> 500
|
||
-- cian (vtorichka, last_seen_at): 748..4329, провалов не было -> 500
|
||
-- domklik (все сегменты, scraped_at): сейчас 62 за 3 суток, сбор
|
||
-- фактически стоит -> 200
|
||
-- Каждый порог лежит между максимумом провала и минимумом здоровых суток:
|
||
-- авито 970 < 1500 < 3542 — исторический случай ловится с запасом в обе стороны.
|
||
--
|
||
-- domklik ЗАБЛОКИРУЕТСЯ СРАЗУ, и это верный исход, а не сбой миграции: источник
|
||
-- подтверждает ~50 строк в сутки, TTL по нему уже один раз (02.08) снёс инвентарь
|
||
-- целиком. Пока сбор не восстановлен, деактивации там нечего подтверждать; протухшие
|
||
-- строки закрываются фильтром свежести на стороне чтения (#2656), а не TTL.
|
||
--
|
||
-- Цена ошибки асимметрична: пропущенная деактивация чинится следующим прогоном,
|
||
-- ложная — только повторным сбором, которого может не быть. Пороги поэтому
|
||
-- смещены в сторону «пропустить прогон».
|
||
--
|
||
-- ЗАВИСИМОСТИ: 052_scrape_schedules.sql (таблица + UNIQUE(source)),
|
||
-- 090/115/160 (сами расписания deactivate_stale_*).
|
||
-- ТОЛЬКО данные (UPDATE default_params), DDL нет.
|
||
-- Идемпотентность + уважение к ручной настройке: ключ проставляется лишь там, где
|
||
-- его ещё нет, поэтому повторный прогон файла не затирает подкрученное оператором
|
||
-- значение. Снять гейт вручную: min_confirmations = 0.
|
||
|
||
BEGIN;
|
||
|
||
UPDATE scrape_schedules
|
||
SET default_params = default_params || jsonb_build_object('min_confirmations', 1500),
|
||
updated_at = NOW()
|
||
WHERE source = 'deactivate_stale_avito'
|
||
AND NOT default_params ? 'min_confirmations';
|
||
|
||
UPDATE scrape_schedules
|
||
SET default_params = default_params || jsonb_build_object('min_confirmations', 500),
|
||
updated_at = NOW()
|
||
WHERE source IN ('deactivate_stale_cian', 'deactivate_stale_yandex')
|
||
AND NOT default_params ? 'min_confirmations';
|
||
|
||
UPDATE scrape_schedules
|
||
SET default_params = default_params || jsonb_build_object('min_confirmations', 200),
|
||
updated_at = NOW()
|
||
WHERE source = 'deactivate_stale_domklik'
|
||
AND NOT default_params ? 'min_confirmations';
|
||
|
||
COMMIT;
|