fix(tradein/avito): бэкфилл простаивал 23 часа из 24 — каденс был суточным #3054

Merged
lekss361 merged 1 commit from fix/avito-backfill-cadence into main 2026-08-22 12:03:40 +00:00
Owner

Продолжение #3049. Транспорт починен и обогащение работает — но очередь не разбирается.

Замер

За сутки после #3049: 238 обогащённых карточек при 9 951 активном объявлении Авито. При таком темпе очередь разбирается месяцами.

Прогоны:

run начало длительность обогащено / попыток исход
4562 21.08 23:00 83 мин 175 / 256 banned
4586 22.08 04:43 17 мин 42 / 70 banned
следующий 23.08 16:53

Причина — планировщик, не скрапинг

compute_next_run_at имеет суточную гранулярность по построению:

interval_days = max(1, int(interval_days))
target = (now + timedelta(days=interval_days)).date()

Меньше суток не выражается. У бэкфилла окно 0-23, поэтому выбирается случайная секунда следующих суток. Прогон при этом умирает по бану через 17-83 минуты — то есть задание работало около часа в сутки, а остальные 23 расписание ждало.

Механизм уже был написан

reschedule_after_minutes появился в #2162 для proxy_healthcheck: ставит next_run_at = now() + interval_minutes сразу после claim, не трогая shared compute_next_run_at. И сам себя тормозит — пока прогон идёт, has_running_run в _claim_run вернёт None и расписание не сбросится.

К бэкфиллу его просто не подключили. Правка — подключение, а не новый механизм.

Про значение 180 минут

Это осознанно консервативная отправная точка, а не найденный оптимум. Данных для подбора нет, и те два прогона, что есть, противоречат наивному ожиданию «пул восстановился за 70 минут, значит можно чаще»: 4586 стартовал через 4.3 часа, когда пул был давно чист (consecutive_fails 0 у всех четырёх), и умер впятеро быстрее предыдущего. Значит память Авито длиннее часов, и учащение способно ухудшить выход, а не улучшить.

Отдельный риск, который надо держать в голове при подборе: те же 4 прокси обслуживают SERP-свипы — первичный сбор. Сжечь их на обогащении хуже, чем медленно обогащать. Двигать интервал вниз только по замеру нескольких суток, глядя и на свипы тоже.

Подбор идёт через default_params расписания — правка кода для этого не нужна.

Проверка

Три теста закрепляют подключённость хука и коридор дефолта, но не конкретное значение: 180 будет двигаться, а вот утрата хука вернёт суточный простой молча.

Фальсификация выполнена: на неизменённом коде все три теста падают, с правкой проходят.

После мержа

Выставить interval_minutes в default_params расписания, если понадобится значение, отличное от дефолта, и смотреть несколько суток — выход бэкфилла и одновременно счётчики свипов.

Продолжение #3049. Транспорт починен и обогащение работает — но очередь не разбирается. ## Замер За сутки после #3049: **238 обогащённых карточек при 9 951 активном объявлении Авито.** При таком темпе очередь разбирается месяцами. Прогоны: | run | начало | длительность | обогащено / попыток | исход | |---|---|---|---|---| | 4562 | 21.08 23:00 | 83 мин | 175 / 256 | banned | | 4586 | 22.08 04:43 | 17 мин | 42 / 70 | banned | | следующий | **23.08 16:53** | — | — | — | ## Причина — планировщик, не скрапинг `compute_next_run_at` имеет суточную гранулярность по построению: ```python interval_days = max(1, int(interval_days)) target = (now + timedelta(days=interval_days)).date() ``` Меньше суток не выражается. У бэкфилла окно 0-23, поэтому выбирается случайная секунда следующих суток. Прогон при этом умирает по бану через 17-83 минуты — то есть задание работало около часа в сутки, а остальные 23 расписание ждало. ## Механизм уже был написан `reschedule_after_minutes` появился в #2162 для `proxy_healthcheck`: ставит `next_run_at = now() + interval_minutes` сразу после claim, не трогая shared `compute_next_run_at`. И сам себя тормозит — пока прогон идёт, `has_running_run` в `_claim_run` вернёт `None` и расписание не сбросится. К бэкфиллу его просто не подключили. Правка — подключение, а не новый механизм. ## Про значение 180 минут Это **осознанно консервативная отправная точка, а не найденный оптимум.** Данных для подбора нет, и те два прогона, что есть, противоречат наивному ожиданию «пул восстановился за 70 минут, значит можно чаще»: 4586 стартовал через 4.3 часа, когда пул был давно чист (`consecutive_fails` 0 у всех четырёх), и умер впятеро быстрее предыдущего. Значит память Авито длиннее часов, и учащение способно ухудшить выход, а не улучшить. Отдельный риск, который надо держать в голове при подборе: **те же 4 прокси обслуживают SERP-свипы** — первичный сбор. Сжечь их на обогащении хуже, чем медленно обогащать. Двигать интервал вниз только по замеру нескольких суток, глядя и на свипы тоже. Подбор идёт через `default_params` расписания — правка кода для этого не нужна. ## Проверка Три теста закрепляют подключённость хука и коридор дефолта, но **не конкретное значение**: 180 будет двигаться, а вот утрата хука вернёт суточный простой молча. Фальсификация выполнена: на неизменённом коде все три теста падают, с правкой проходят. ## После мержа Выставить `interval_minutes` в `default_params` расписания, если понадобится значение, отличное от дефолта, и смотреть несколько суток — выход бэкфилла и одновременно счётчики свипов.
lekss361 added 1 commit 2026-08-22 11:57:50 +00:00
fix(tradein/avito): бэкфилл простаивал 23 часа из 24 — каденс был суточным
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 4m47s
fa1399d59e
Замер 2026-08-22, уже после починки транспорта (#3049): обогащение работает,
но очередь не разбирается. За сутки 238 карточек при 9 951 активном объявлении.

Причина в планировщике, а не в скрапинге. `compute_next_run_at` имеет суточную
гранулярность по построению — `interval_days = max(1, int(...))`, целевая дата
`now + interval_days`. Меньше суток не выражается. Бэкфилл при этом умирает по
бану через 17-83 минуты, то есть работал около часа в сутки, а остальное время
расписание ждало следующего дня.

Механизм sub-hourly каденса уже был написан — `reschedule_after_minutes`
(#2162, сделан для proxy_healthcheck). Его просто не подключили к бэкфиллу.
Хук ставит next_run_at = now() + interval_minutes сразу после claim и сам себя
тормозит: пока прогон идёт, has_running_run в _claim_run возвращает None.

180 минут — осознанно консервативная отправная точка, НЕ найденный оптимум.
Данных для подбора нет, и имеющиеся два прогона противоречат наивному
ожиданию: 4562 дал 175 карточек за 83 минуты, а 4586 через 4.3 часа — когда
пул прокси был давно чист — умер за 17 минут с 42 карточками. Значит память
Авито длиннее часов, и учащение может ухудшить выход.

Отдельно держать в голове при подборе: те же 4 прокси обслуживают SERP-свипы,
то есть первичный сбор. Сжечь их на обогащении хуже, чем медленно обогащать.
Двигать интервал вниз только по замеру нескольких суток, глядя и на свипы.
Подбор — через default_params расписания, правка кода для этого не нужна.

Тесты закрепляют подключённость хука и коридор дефолта, а не конкретное
значение: 180 будет двигаться, а вот утрата хука вернёт суточный простой
молча. Проверено фальсификацией — на неизменённом коде все три падают.
lekss361 merged commit b5b7a8246e into main 2026-08-22 12:03:40 +00:00
lekss361 deleted branch fix/avito-backfill-cadence 2026-08-22 12:03:40 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3054
No description provided.