imv: HTTP 429 больше не приговаривает дом навечно #3314
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3314
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/imv-429-transient"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Из вечерних алертов 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)
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 разбирает 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 (починка разбора не чинит строки сама).