fix(tradein/proxy): отличать ручное выключение узла от авто-выключения (#2610) #2652
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#2652
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/tradein-proxy-disabled-reason"
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?
Summary
#2610 (находка ревью PR #2609). #2609 сделал
mark_health(ok=True)безусловно ставящимenabled=true— это лечило реальный прод-инцидент (авто-выключенный узел больше никогда не проверялся, транзиентный сбой = вечный приговор). Побочка: узел, снятый оператором руками, молча возвращался в строй первой же ipify-пробой. Особенно больно в главном рабочем сценарии — узел выключили из-за бана площадкой, а ipify никого не банит → проба всегда проходит → узел воскресает гарантированно, и снимать приходится снова и снова.Колонка
scrape_proxies.disabled_reason text(миграция 209,ADD COLUMN IF NOT EXISTS, без DEFAULT — метаданные, без переписывания таблицы).NULL= не выключен вручную; авто-выключение поconsecutive_failsтоже оставляет NULL, поэтому поведение #2609 полностью сохранено.Почему текст, а не булев
manually_disabled: #2600 п.1 добавит третью причину («бан площадкой») — она ляжет в ту же колонку как'banned:avito'без новой миграции, и значение само документирует причину. Все проверки ветвятся наIS NULL, а не на значение.Охват (ревью подтвердило исчерпывающим грепом — всего 4 сайта записи
enabled):mark_healthok-ветка — гейтdisabled_reason IS NULL+ лог пропуска воскрешения (раньше молча);mark_healthfail-ветка — причину не трогает (авто-выключенные остаются воскресаемыми);bulk_upsert_proxies— второй unconditional-enable, которого issue не называл (егоON CONFLICTтоже безусловно включал узел при ре-апсерте);patch_proxy—enabled=Falseпишет причину,enabled=Trueбезусловно сбрасывает её (иначе узел, выключенный однажды, больше никогда не был бы авто-восстановим).run_proxy_healthcheckпродолжает пробовать ручно-выключенные узлы (метрики/exit_ip свежие, узел готов к работе сразу после включения), но счётчикrevivedсчитает только настоящие воскрешения.disabled_reasonотдаётся вGET /proxiesиPATCH /proxies/{id}— оператор видит причину.Test plan
bulk_upsertсохраняет ручное выключение при ре-апсертеtests/services/test_proxy_pool.py+tests/test_admin_proxies.py= 45 passed; полный сьют 3277 passed (1 known pre-existing); ruff чистоGET /proxiesотдаёт полеReview
code-reviewer: ✅ APPROVE. Сам стэшил реализацию и убедился, что 3 новых теста реально красные на до-#2610 коде (не тавтология); проверил все переходы состояний (manual → auto-fail → auto-disable не «понижается» до авто-воскрешаемого); мок в тестах ветвится на реальных SQL-подстроках, а не хардкодит исход. Два косметических минора (пустая строка как reason; нет теста на ре-выключение без reason) — не блокеры.
Про будущее (вход в #2600 п.1): текущая колонка достаточна для третьей причины без миграции, но не даёт авто-истечения бана — если бан площадки временный, понадобится
banned_untilили парсинг timestamp из значения. Осознанно отложено до самой задачи.Refs #2610