fix(tradein): single-run guard на avito-city-sweep admin-endpoint #874

Merged
bot-reviewer merged 1 commit from fix/avito-sweep-single-run-guard into main 2026-05-31 08:55:34 +00:00
Owner

Summary

Параллельные avito-sweep'ы делят один прокси-IP → удвоенный rate → Avito бан.

Incident 2026-05-31 (verified по scrape_runs): runs #26 (08:31:29–08:42:50) и #27 (08:38:09–08:43:40) шли ОДНОВРЕМЕННО → оба banned. Это и скомпрометировало delay-эксперимент (казалось «5s банится», а на деле дубль).

Scheduler уже защищён (has_running_run + advisory lock в _claim_run), но ручной admin-endpoint POST /scrape/avito-city-sweep guard'а НЕ имел → два ручных триггера проходили.

  • admin.py: has_running_run('avito_city_sweep')HTTPException 409 перед create_run (до background task — run-row не создаётся).
  • test: monkeypatch has_running_run→True → 409.

Test plan

  • ruff clean; pytest tests/test_api_avito_stage4a.py → 6 passed
  • code-reviewer: APPROVE (no blockers; import-граф ацикличен)
  • Post-deploy: 2× POST /scrape/avito-city-sweep подряд → второй 409

Noted follow-ups (не блокируют): TOCTOU на ручном endpoint (sub-second двойной POST) — при необходимости переиспользовать advisory-lock из _claim_run; опц. включить blocking run_id в 409-detail.

## Summary Параллельные avito-sweep'ы делят один прокси-IP → удвоенный rate → Avito бан. **Incident 2026-05-31 (verified по scrape_runs):** runs **#26** (08:31:29–08:42:50) и **#27** (08:38:09–08:43:40) шли ОДНОВРЕМЕННО → оба `banned`. Это и скомпрометировало delay-эксперимент (казалось «5s банится», а на деле дубль). Scheduler уже защищён (`has_running_run` + advisory lock в `_claim_run`), но ручной admin-endpoint `POST /scrape/avito-city-sweep` guard'а НЕ имел → два ручных триггера проходили. - `admin.py`: `has_running_run('avito_city_sweep')` → `HTTPException 409` перед `create_run` (до background task — run-row не создаётся). - test: monkeypatch `has_running_run`→True → 409. ## Test plan - [x] ruff clean; `pytest tests/test_api_avito_stage4a.py` → 6 passed - [x] code-reviewer: ✅ APPROVE (no blockers; import-граф ацикличен) - [ ] Post-deploy: 2× POST /scrape/avito-city-sweep подряд → второй 409 Noted follow-ups (не блокируют): TOCTOU на ручном endpoint (sub-second двойной POST) — при необходимости переиспользовать advisory-lock из `_claim_run`; опц. включить blocking run_id в 409-detail.
lekss361 added 1 commit 2026-05-31 08:54:15 +00:00
Параллельные avito-sweep'ы делят один прокси-IP → удвоенный rate → Avito бан.
Incident 2026-05-31: runs #26 (08:31-08:42) и #27 (08:38-08:43) шли
одновременно → оба banned (скомпрометировало delay-эксперимент). Scheduler
уже защищён (has_running_run + advisory lock в _claim_run), но ручной
admin-endpoint POST /scrape/avito-city-sweep guard'а не имел.

- admin.py: has_running_run('avito_city_sweep') → HTTPException 409 перед create_run.
- test: monkeypatch has_running_run→True → 409.
bot-reviewer approved these changes 2026-05-31 08:55:14 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — single-run guard на ручном avito-city-sweep endpoint.

Cruxes проверены:

  • has_running_run(db: Session, source: str) -> bool существует (scheduler.py:87) — сигнатура совпадает с вызовом has_running_run(db, "avito_city_sweep").
  • Циклического импорта нет: scheduler.py не импортит admin/app.api (admin→scheduler односторонний). Подтверждает «import-граф ацикличен».
  • Guard стоит до runs_mod.create_run → при 409 orphan run-row не создаётся. ✓
  • Тест monkeypatch'ит admin_module.has_running_run — корректно перекрывает имя из from ... import в неймспейсе admin.

Incident-grounded: runs #26+#27 параллельно → оба banned (делят прокси-IP). Scheduler уже защищён (has_running_run + advisory lock в _claim_run); этот guard закрывает ручной admin-триггер. TOCTOU (sub-second двойной POST) честно вынесен в non-blocking follow-up — практический gap (раны 11 мин врозь) закрыт.

6 тестов pass, own code-reviewer . admin.py + test, SQL/секретов/self-extending нет.

Мержу. (Incident hotfix, без linked issue.)

<!-- gendesign-review-bot: sha=d9d6caa verdict=approve --> ✅ **APPROVE** — single-run guard на ручном avito-city-sweep endpoint. **Cruxes проверены:** - `has_running_run(db: Session, source: str) -> bool` существует (scheduler.py:87) — сигнатура совпадает с вызовом `has_running_run(db, "avito_city_sweep")`. - Циклического импорта нет: scheduler.py не импортит `admin`/`app.api` (admin→scheduler односторонний). Подтверждает «import-граф ацикличен». - Guard стоит **до** `runs_mod.create_run` → при 409 orphan run-row не создаётся. ✓ - Тест monkeypatch'ит `admin_module.has_running_run` — корректно перекрывает имя из `from ... import` в неймспейсе admin. Incident-grounded: runs #26+#27 параллельно → оба `banned` (делят прокси-IP). Scheduler уже защищён (`has_running_run` + advisory lock в `_claim_run`); этот guard закрывает ручной admin-триггер. TOCTOU (sub-second двойной POST) честно вынесен в non-blocking follow-up — практический gap (раны 11 мин врозь) закрыт. 6 тестов pass, own code-reviewer ✅. admin.py + test, SQL/секретов/self-extending нет. Мержу. (Incident hotfix, без linked issue.)
bot-reviewer merged commit 997eda489c into main 2026-05-31 08:55:34 +00:00
bot-reviewer deleted branch fix/avito-sweep-single-run-guard 2026-05-31 08:55:34 +00:00
Sign in to join this conversation.
No reviewers
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#874
No description provided.