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
53 lines
4 KiB
PL/PgSQL
53 lines
4 KiB
PL/PgSQL
-- 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;
|