imv: HTTP 429 больше не приговаривает дом навечно #3314

Merged
bot-backend merged 1 commit from fix/imv-429-transient into main 2026-09-01 16:27:55 +00:00
Collaborator

Из вечерних алертов 01.09 (house_imv: RuntimeError('HTTP 429') / ('HTTP 400'), поток по штуке в минуту).

Механизм

_raise_for_status_categorized в providers/avito/imv.py разбирает 401/403 (→ auth) и 5xx (→ transient), а весь остальной 4xx проваливается в resp.raise_for_status() и приезжает в house_imv_backfill голым RuntimeError. Бэкфилл типизирует только IMV*-исключения — дом получает терминальный imv_status='error' и не попадает в повторные пакеты никогда.

429 — канонический временный отказ, и механика повтора для таких в системе есть и работает (transient_error + retry-lane + лимит попыток из #2674). Просто 429 до неё не доезжал.

Замер ущерба (прод, 01.09)

imv_status домов из них «HTTP 429» из них «HTTP 400»
error (терминальный) 93 19 35

19 домов заперты навечно за отказ, который по своей природе ретраебелен.

Правка

429 и 408 → IMVTransientError. Одна ветка в классификаторе — все вызывающие (backfill, estimator) уже умеют с ней обращаться.

400 намеренно оставлен терминальным. Тело безликое {"code":400,"message":"Bad Request"}, оснований считать его временным нет, а ретраебельный 400 означал бы вечно долбить дома с действительно кривыми параметрами. Тест держит границу с обеих сторон: и «429 → transient», и «400 → НЕ transient».

Проверки

9 тестов. Фальсификация: снятие ветки 408/429 даёт 2 failed по значению (IMVTransientError не поднят), не ImportError. ruff check / format --check чисто.

После мержа

Ремонт уже запертых строк отдельным шагом — починка разбора не чинит строки сама: UPDATE houses SET imv_status='transient_error' WHERE imv_status='error' AND imv_error_reason LIKE '%429%' (19 строк), дальше их подберёт штатный retry-lane. Сделаю после деплоя и отчитаюсь числами.

Из вечерних алертов 01.09 (`house_imv: RuntimeError('HTTP 429')` / `('HTTP 400')`, поток по штуке в минуту). ## Механизм `_raise_for_status_categorized` в `providers/avito/imv.py` разбирает 401/403 (→ auth) и 5xx (→ transient), а **весь остальной 4xx проваливается** в `resp.raise_for_status()` и приезжает в `house_imv_backfill` голым `RuntimeError`. Бэкфилл типизирует только `IMV*`-исключения — дом получает **терминальный** `imv_status='error'` и не попадает в повторные пакеты никогда. 429 — канонический *временный* отказ, и механика повтора для таких в системе есть и работает (`transient_error` + retry-lane + лимит попыток из #2674). Просто 429 до неё не доезжал. ## Замер ущерба (прод, 01.09) | imv_status | домов | из них «HTTP 429» | из них «HTTP 400» | |---|---|---|---| | error (терминальный) | 93 | **19** | 35 | 19 домов заперты навечно за отказ, который по своей природе ретраебелен. ## Правка 429 и 408 → `IMVTransientError`. Одна ветка в классификаторе — все вызывающие (backfill, estimator) уже умеют с ней обращаться. **400 намеренно оставлен терминальным.** Тело безликое `{"code":400,"message":"Bad Request"}`, оснований считать его временным нет, а ретраебельный 400 означал бы вечно долбить дома с действительно кривыми параметрами. Тест держит границу **с обеих сторон**: и «429 → transient», и «400 → НЕ transient». ## Проверки 9 тестов. Фальсификация: снятие ветки 408/429 даёт **2 failed по значению** (`IMVTransientError` не поднят), не ImportError. `ruff check` / `format --check` чисто. ## После мержа Ремонт уже запертых строк отдельным шагом — починка разбора не чинит строки сама: `UPDATE houses SET imv_status='transient_error' WHERE imv_status='error' AND imv_error_reason LIKE '%429%'` (19 строк), дальше их подберёт штатный retry-lane. Сделаю после деплоя и отчитаюсь числами.
bot-backend added 1 commit 2026-09-01 16:22:19 +00:00
imv: HTTP 429 больше не приговаривает дом навечно
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m50s
dab2b43efc
Алерты 01.09 (house_imv: RuntimeError('HTTP 429') / ('HTTP 400')) вскрыли
дыру в классификаторе: _raise_for_status_categorized разбирает 401/403 и 5xx,
а ВЕСЬ остальной 4xx проваливается в resp.raise_for_status() и приезжает в
house_imv_backfill голым RuntimeError. Бэкфилл типизирует только
IMV*-исключения — дом получает ТЕРМИНАЛЬНЫЙ imv_status='error' и выпадает из
повторных пакетов навсегда.

429 — канонический ВРЕМЕННЫЙ отказ (rate limit), и механика повтора для таких
существует (transient_error + retry-lane + лимит попыток #2674). Замер на
проде: 19 домов заперты в error с причиной «HTTP 429» — ретраебельный отказ
стал вечным приговором.

429 и 408 теперь IMVTransientError. 400 НАМЕРЕННО оставлен терминальным: тело
безликое {"code":400,"message":"Bad Request"}, оснований считать его
временным нет, а ретраебельный 400 значил бы вечно долбить дома с реально
кривыми параметрами. Тест держит границу С ОБЕИХ СТОРОН — и «429 transient»,
и «400 НЕ transient».

Фальсификация: снятие ветки 408/429 даёт 2 failed по значению
(IMVTransientError не поднят), не ImportError. 9 passed, ruff чисто.

Ремонт уже запертых строк — отдельным шагом после мержа: UPDATE 19 домов
error→transient_error (починка разбора не чинит строки сама).
bot-backend merged commit 4fe0538ea0 into main 2026-09-01 16:27:55 +00:00
bot-backend deleted branch fix/imv-429-transient 2026-09-01 16:27:55 +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#3314
No description provided.