gendesign/tradein-mvp/backend
bot-backend d9b4f124a6
All checks were successful
CI / changes (pull_request) Successful in 10s
CI Trade-In / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (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 4m24s
CI / backend-tests (pull_request) Has been skipped
feat(tradein/scheduler): планировщик подхватывает чекпоинт оборванного прогона (#930)
#930 сделал обе половины механизма — запись точки (counters.done_buckets) и её
чтение (run_*_full_load(resume_run_id=...)) — но единственным входом оставил
админку. У avito full-load её нет вовсе, а планировщик передавал resume_run_id
литеральным None. То есть боевого пути возобновления не существовало ни дня:
433 корзины в 30 оборванных прогонах за 90 суток (avito 242, cian 134,
exhaustive 57) перебирались заново, включая 35 корзин прогона 3547, убитого
деплоем на третьем часу и лежащего с 09.08.

Одной строки resume_run_id=prev было бы мало и опасно — правка из четырёх частей.

1. Полнота корзины (иначе видимая потеря стала бы невидимой). Ключ
   done_buckets одинаков у целиком и частично собранной корзины, а частичность
   возникает тремя путями: страница молча выпала (page_html=None), исключение
   страницы проглочено gather'ом, признанный tail-loss/hard-cap. SERP-слой
   теперь отдаёт признак полноты третьим аргументом on_bucket, пайплайн пишет
   в чекпоинт ТОЛЬКО полную корзину, частичные считает (partial_buckets).

2. Точка стала монотонной. update_heartbeat/mark_* мержат counters-jsonb
   вместо замены: раньше _on_progress и фоновый heartbeat cian'а (каждые 60 с)
   слали counters без done_buckets и СТИРАЛИ точку, а mark_failed уничтожал её
   насовсем — 15 оборванных прогонов с 45k собранных лотов и без ключа вовсе.

3. Тождество задания. Кандидат — ПОСЛЕДНИЙ прогон того же source (после 'done'
   возобновлять нечего), params сверяются побайтово: incremental_days меняет
   СМЫСЛ ключа, price_cap_per_bucket — само дерево бисекции. Статусы banned/
   cancelled/failed; zombie исключён намеренно (reap не убивает процесс,
   точка может двигаться). Срок годности — такт источника плюс сутки сетки
   запуска. Цепочка возобновлений ограничена STALE_DIGEST_INTERVAL_FACTOR-1.

4. Наблюдаемость. Вердикт (resume_from/resume_reason/resume_buckets/
   resume_chain) пишется в counters нового прогона: no_prev_run, status_*,
   params_changed, no_checkpoint, checkpoint_stale, chain_limit, ok.

Плюс skip_buckets доехал до инкрементальной ветки avito — без этого resume в
боевом режиме avito_full_load (incremental_days=7) был бы чистым no-op.
2026-08-12 21:40:41 +05:00
..
app fix(tradein/imv): «временная» ошибка снова временная — 1390 домов возвращаются в очередь (#2843) 2026-08-12 16:06:24 +00:00
data/sql fix(tradein/imv): «временная» ошибка снова временная — 1390 домов возвращаются в очередь (#2843) 2026-08-12 16:06:24 +00:00
scripts fix(tradein/scraper): дневной снимок узнаёт свой прогон (#2701) (#2707) 2026-08-06 07:00:17 +00:00
tests feat(tradein/scheduler): планировщик подхватывает чекпоинт оборванного прогона (#930) 2026-08-12 21:40:41 +05:00
.dockerignore feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
Dockerfile feat(tradein): версионирование продукта — единый источник, подвал, PDF, /versions (#2824) 2026-08-10 16:00:54 +00:00
pyproject.toml feat(tradein/auth): password hashing + session config foundation (#2550) 2026-07-30 09:40:51 +03:00