tradein: две живые копии mark_failed/mark_done с разной семантикой counters — app/services/scrape_runs.py ЗАМЕНЯЕТ, scraper_kit/orchestration/runs.py МЕРЖИТ (||) #3390

Closed
opened 2026-09-06 01:31:46 +00:00 by bot-backend · 1 comment
Collaborator

Находка доработки PR #3388 (#3384), подтверждённая по импорту: app/services/scheduler.py:50, avito_detail_backfill.py:90, domclick_detail_backfill.py:108 импортируют app.services.scrape_runs as runs_mod, где mark_failed пишет counters = CAST(:counters AS jsonb) (замена, scrape_runs.py:738); kit-копия scraper_kit/orchestration/runs.py:~817counters = COALESCE(counters,'{}') || CAST(:counters AS jsonb) (мерж). Свипы через kit-scheduler идут на мерж, detail-бэкфиллы через runs_mod — на замену (scheduler.py:31 об этом предупреждает).

Чем это уже стоило: code-review #3388 предложил «отдать в mark_failed только {"no_proxy_stop": 1}, остальное домержится» — на replace-семантике это стёрло бы измеренные counters начисто; в #3355 я сам принял от ревью ложное «writer overwrites counters» про kit-путь (опровергнуто grep'ом по импорту). Две копии одной функции с противоположной семантикой — источник ложных выводов у людей и агентов.

Что сделать: одна реализация (kit runs.py), app-модуль — тонкий реэкспорт/адаптер с той же семантикой (мерж), либо явный replace_counters=True для тех, кому нужна замена; тест на семантику по значению (heartbeat записал a=5, mark_failed({b:1}) → в БД a=5, b=1) для ОБОИХ путей импорта; grep всех mark_failed(/mark_done( вызовов и проверка, кто полагается на замену (например, финальный counters.to_dict() у avito/domclick — при мерже поверх heartbeat остаётся тем же).

Refs #3384, PR #3388, #3355, память two-reviews-disagree-check-the-import.

Находка доработки PR #3388 (#3384), подтверждённая по импорту: `app/services/scheduler.py:50`, `avito_detail_backfill.py:90`, `domclick_detail_backfill.py:108` импортируют `app.services.scrape_runs as runs_mod`, где `mark_failed` пишет `counters = CAST(:counters AS jsonb)` (**замена**, `scrape_runs.py:738`); kit-копия `scraper_kit/orchestration/runs.py:~817` — `counters = COALESCE(counters,'{}') || CAST(:counters AS jsonb)` (**мерж**). Свипы через kit-scheduler идут на мерж, detail-бэкфиллы через `runs_mod` — на замену (`scheduler.py:31` об этом предупреждает). Чем это уже стоило: code-review #3388 предложил «отдать в `mark_failed` только `{"no_proxy_stop": 1}`, остальное домержится» — на replace-семантике это стёрло бы измеренные counters начисто; в #3355 я сам принял от ревью ложное «writer overwrites counters» про kit-путь (опровергнуто grep'ом по импорту). Две копии одной функции с противоположной семантикой — источник ложных выводов у людей и агентов. **Что сделать:** одна реализация (kit `runs.py`), app-модуль — тонкий реэкспорт/адаптер с той же семантикой (мерж), либо явный `replace_counters=True` для тех, кому нужна замена; тест на семантику по значению (heartbeat записал `a=5`, `mark_failed({b:1})` → в БД `a=5, b=1`) для ОБОИХ путей импорта; grep всех `mark_failed(`/`mark_done(` вызовов и проверка, кто полагается на замену (например, финальный `counters.to_dict()` у avito/domclick — при мерже поверх heartbeat остаётся тем же). Refs #3384, PR #3388, #3355, память `two-reviews-disagree-check-the-import`.
Author
Collaborator

PR #3400 смержен и задеплоен (06.09 ~08:26 UTC, BUILD_SHA=06ad504 в backend и scraper; app/services/scrape_runs.py в контейнере — 36 строк с sys.modules-алиасом; scraper стартовал без трейсбеков, boot-reap 0). Приёмка: у app-задач финализированные прогоны сохраняют ключи последнего heartbeat (counters ⊇ пульс), interrupted/done_buckets переживают финализатор; проверю на ближайших avito/domclick_detail_backfill. Follow-up (не блокер): фраза «обе копии» ещё живёт в докстрингах test_3393:19,178, test_3044:10, test_2764:12 — инертна; схлопывание двух имён kit_runs/runs_mod в scheduler.py — отдельный PR.

PR #3400 смержен и задеплоен (06.09 ~08:26 UTC, `BUILD_SHA=06ad504` в backend и scraper; `app/services/scrape_runs.py` в контейнере — 36 строк с `sys.modules`-алиасом; scraper стартовал без трейсбеков, boot-reap 0). Приёмка: у app-задач финализированные прогоны сохраняют ключи последнего heartbeat (counters ⊇ пульс), `interrupted`/`done_buckets` переживают финализатор; проверю на ближайших `avito/domclick_detail_backfill`. Follow-up (не блокер): фраза «обе копии» ещё живёт в докстрингах `test_3393:19,178`, `test_3044:10`, `test_2764:12` — инертна; схлопывание двух имён `kit_runs`/`runs_mod` в `scheduler.py` — отдельный PR.
Sign in to join this conversation.
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#3390
No description provided.