yandex_city_sweep: combo с упавшим сохранением уходит в чекпоинт — молчаливая дыра в покрытии #3170

Closed
opened 2026-08-27 21:15:11 +00:00 by bot-backend · 1 comment
Collaborator

Найдено при ревью PR #3169 (тот же дефект был в новом коде и там исправлен). Здесь он уже в main и работает на проде.

Дефект

run_yandex_city_sweep, колбэк _on_combopackages/scraper-kit/src/scraper_kit/orchestration/pipeline.py:2327:

done_combos.add(combo_label)        # ← строка 2327: отметка ДО сохранения
...
try:
    ins, upd = save_listings(...)   # ← строка 2340
except Exception as save_exc:       # ← строка 2352: исключение перехвачено
    ...
    db.rollback()
runs.update_heartbeat(db, run_id, {..., "done_buckets": sorted(done_combos)})

Combo уходит в done_buckets до попытки сохранения, а отказ save_listings перехватывается и не пробрасывается. Значит combo, чьи лоты не сохранились, помечается пройденным.

Чем проявляется

Следующий прогон читает done_buckets и пропускает этот combo — навсегда. Причём молча: прогон завершается со статусом done, счётчики показывают успех, просто часть выдачи (сегмент × комнатность × ценовой диапазон) не собирается никогда. Ровно тот сценарий, ради которого затевался #3074.

Перехват исключения сам по себе осознан — одна упавшая единица не должна ронять весь sweep. Неверна только отметка.

Как сделано правильно у соседей

  • run_cian_full_load_mark_bucket(bucket_key, complete) (pipeline.py:3370): признак полноты приезжает отдельным аргументом, частичный бакет считается, но в чекпоинт не пишется.
  • run_avito_city_sweep (:1821) — отдельный флаг _anchor_ok, потому что успех и неудача сходятся в одной строке.
  • cian_city_sweep (:3228) — граница проведена потоком управления (return / continue), отметка недостижима с ветки отказа.
  • PR #3169 (avito_newbuilding_sweep) — флаг _saved_ok.

Сопутствующее

Проверить заодно, как run_yandex_city_sweep вычисляет точку подхвата. В #3169 обнаружилось, что max(done)+1 перепрыгивает дыру в чекпоинте навсегда; если здесь подхват тоже опирается на максимум, а не на членство в множестве, дефект удваивается.

Приёмка

  • Combo с упавшим save_listings не попадает в done_buckets
  • Тест падает при возвращении дефекта (проверить обратимость, как в #3169)
  • Проверено, что подхват опирается на членство в множестве, а не на максимум

Refs #3074, #3169, #2989

Найдено при ревью PR #3169 (тот же дефект был в новом коде и там исправлен). Здесь он **уже в `main` и работает на проде**. ## Дефект `run_yandex_city_sweep`, колбэк `_on_combo` — `packages/scraper-kit/src/scraper_kit/orchestration/pipeline.py:2327`: ``` done_combos.add(combo_label) # ← строка 2327: отметка ДО сохранения ... try: ins, upd = save_listings(...) # ← строка 2340 except Exception as save_exc: # ← строка 2352: исключение перехвачено ... db.rollback() runs.update_heartbeat(db, run_id, {..., "done_buckets": sorted(done_combos)}) ``` Combo уходит в `done_buckets` до попытки сохранения, а отказ `save_listings` перехватывается и не пробрасывается. Значит **combo, чьи лоты не сохранились, помечается пройденным**. ## Чем проявляется Следующий прогон читает `done_buckets` и пропускает этот combo — навсегда. Причём **молча**: прогон завершается со статусом `done`, счётчики показывают успех, просто часть выдачи (сегмент × комнатность × ценовой диапазон) не собирается никогда. Ровно тот сценарий, ради которого затевался #3074. Перехват исключения сам по себе осознан — одна упавшая единица не должна ронять весь sweep. Неверна только отметка. ## Как сделано правильно у соседей - `run_cian_full_load` — `_mark_bucket(bucket_key, complete)` (`pipeline.py:3370`): признак полноты приезжает отдельным аргументом, частичный бакет считается, но в чекпоинт не пишется. - `run_avito_city_sweep` (`:1821`) — отдельный флаг `_anchor_ok`, потому что успех и неудача сходятся в одной строке. - `cian_city_sweep` (`:3228`) — граница проведена потоком управления (`return` / `continue`), отметка недостижима с ветки отказа. - PR #3169 (`avito_newbuilding_sweep`) — флаг `_saved_ok`. ## Сопутствующее Проверить заодно, как `run_yandex_city_sweep` вычисляет точку подхвата. В #3169 обнаружилось, что `max(done)+1` перепрыгивает дыру в чекпоинте навсегда; если здесь подхват тоже опирается на максимум, а не на членство в множестве, дефект удваивается. ## Приёмка - [ ] Combo с упавшим `save_listings` не попадает в `done_buckets` - [ ] Тест падает при возвращении дефекта (проверить обратимость, как в #3169) - [ ] Проверено, что подхват опирается на членство в множестве, а не на максимум Refs #3074, #3169, #2989
bot-backend added the
bug
data
priority/p1
scope/backend
scrapers
tradein
labels 2026-08-27 21:15:11 +00:00
Owner

Проверено в коде на forgejo/main — сделано, закрываю.

PR #3173 (merged 2026-08-27) — чекпоинт ставится ПОСЛЕ save_listing; закреплено tests/test_3170_yandex_combo_checkpoint.py (оба направления).

Проверено в коде на forgejo/main — сделано, закрываю. PR #3173 (merged 2026-08-27) — чекпоинт ставится ПОСЛЕ save_listing; закреплено tests/test_3170_yandex_combo_checkpoint.py (оба направления).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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#3170
No description provided.