fix(ptica): download_binary переживает транзиентный ответ, как и get_json (#2464) #2999
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#2999
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/2464-download-binary-retry"
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?
Дефект
get_jsonиdownload_binaryживут в одном классе, ходят через один браузерный контекст и попадают под один и тот же WAF. Но:get_jsondownload_binaryОдин 429 ронял загрузку картинки насовсем. Вызывающий (
download_plan_image,download_photos) ловит исключение и пишет в лог «не удалось» — неотличимо от «файла нет».Правильный образец лежал в этом же классе, двадцатью строками выше.
Правка
Ретраи по образцу
get_json. Непереходные коды (403, 404) поднимаются сразу, без ожидания: повтор их не изменит, а лишний стук под WAF вредит.Разбор статуса вынесен за семафор —
sleepне должен держать слот, иначе backoff одной картинки тормозит остальные.Как проверено
origin/mainтранзиентные тесты красные с конкретным значением —вместо байтов получили RuntimeError('binary http 429: rate limited'); попыток=1. Ни одного ImportError/TypeError.[1, 2]. Без него цикл безsleepвыглядел бы в тесте так же, как с ним, — а под WAF разница решающая.exhausted, а не пустые байты, успех с первой попытки не порождает лишних запросов и пауз.exceptвget_json.download_binaryна двойнике Playwright-контекста, а не проверяют текст функции.pytest backend/tests/services/scrapers/— 340 passed, 6 skipped.Часть эпика #2464.
Обе функции ходят через один браузерный контекст, под один и тот же WAF. `get_json` держит до пяти попыток с экспоненциальным backoff на 429/5xx/0, а `download_binary` не имел ретраев вовсе: один 429 ронял загрузку картинки насовсем, и вызывающий (`download_plan_image`, `download_photos`) писал в лог «не удалось» — неотличимо от «файла нет». Правильный образец лежал в этом же классе, двадцатью строками выше. Непереходные коды (403, 404) поднимаются сразу, без ожидания: повтор их не изменит, а лишний стук под WAF вредит. Разбор статуса вынесен ЗА семафор — sleep не должен держать слот. Двусторонне: против origin/main транзиентные тесты красные с конкретным значением («вместо байтов получили RuntimeError('binary http 429…'); попыток=1»), ни одного ImportError/TypeError. Контроли зелёные с обеих сторон: 403 и 404 не повторяются, исчерпание попыток даёт честную ошибку, а не пустые байты, успех с первой попытки не порождает лишних запросов. Отдельный контроль на паузы: без него «ретраит» и «долбит без пауз» неотличимы в тесте, а под WAF разница между ними решающая — проверяется, что задержки растут как 1, 2 секунды. pytest backend/tests/services/scrapers/ — 340 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>