gendesign/tradein-mvp/backend/data/sql/209_scrape_proxies_disabled_reason.sql
bot-backend aa5bb76822
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 2m35s
Deploy Trade-In / build-backend (push) Successful in 58s
Deploy Trade-In / deploy (push) Successful in 1m17s
fix(tradein/proxy): отличать ручное выключение узла от авто-выключения (#2610) (#2652)
2026-08-05 10:18:02 +00:00

53 lines
4 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 209_scrape_proxies_disabled_reason.sql
-- scrape_proxies.disabled_reason — различить "оператор выключил руками" от
-- "пул выключил сам после серии сбоев" (#2610).
--
-- WHY:
-- #2609 сделало mark_health(ok=True) безусловно ставить enabled=true — чинит
-- реальный прод-инцидент (авто-выключенный после серии сбоев узел иначе не
-- проверяется больше никогда, транзиентный сбой = вечный приговор). Побочка:
-- оператор снимает узел с ротации через PATCH /proxies/{id} (enabled=false) —
-- первая же успешная ipify-проба молча возвращает его обратно. Особенно больно,
-- когда узел забанен площадкой (Авито): ipify через него ходит чисто (ipify
-- никого не банит), значит узел гарантированно вернётся, и оператор снимает
-- его снова и снова.
--
-- WHAT:
-- disabled_reason text, NULL по умолчанию. Семантика:
-- NULL — узел не выключен вручную (авто-disable по consecutive_fails —
-- тоже NULL здесь; поведение #2609 "авто-выключенный воскресает
-- первой успешной пробой" сохраняется без изменений).
-- текст — причина ручного выключения (по умолчанию из admin API —
-- "manually disabled via admin API", либо то, что передал оператор).
-- mark_health(ok=True) НЕ трогает enabled, пока это поле не NULL.
-- Сбрасывается в NULL ручным включением (PATCH .../{id} enabled=true).
--
-- ВЫБОР text, а не boolean manually_disabled: единственное текстовое поле
-- расширяемо под будущую ТРЕТЬЮ причину выключения без новой миграции — #2600
-- п.1 (сигнал бана площадкой до пула) заведёт значение вида 'banned:avito',
-- отличимое от 'manual' в логах/админке, и по той же самой колонке (не-NULL =
-- не воскрешать по голому ipify) без ALTER TABLE. Boolean такого не даёт —
-- потребовал бы либо второй колонки, либо потери "почему" при разборе.
--
-- IDEMPOTENCY / SAFETY:
-- - BEGIN/COMMIT — атомарно.
-- - ADD COLUMN IF NOT EXISTS — повторный прогон no-op (auto-apply strict).
-- - Без DEFAULT — существующие строки получают NULL, т.е. "не выключены
-- руками" — обратная совместимость: ни одна прод-строка не станет ручной.
--
-- Dependencies: 157_scrape_proxies.sql
BEGIN;
ALTER TABLE scrape_proxies
ADD COLUMN IF NOT EXISTS disabled_reason text;
COMMENT ON COLUMN scrape_proxies.disabled_reason IS
'NULL = не выключен вручную (mark_health(ok=True) может авто-восстановить '
'enabled=true, #2609). Текст = причина ручного выключения оператором '
'(PATCH /proxies/{id} enabled=false, admin.py) — ipify-проба узел НЕ '
'воскрешает, пока поле не NULL. Сбрасывается в NULL ручным включением. '
'Задел под #2600 п.1 (сигнал бана площадкой до пула) — третья причина '
'ляжет сюда же без новой миграции, напр. значением вида ''banned:avito''.';
COMMIT;