fix(tradein/payments): SET LOCAL lock_timeout в миграции 240 (gate threshold — артефакт)
All checks were successful
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m1s
CI Trade-In / backend-tests (pull_request) Successful in 4m1s

check-migration-lock-timeout.py требует lock_timeout только для NN >= 250 в
tradein — порог назначен по номеру аварийной миграции 250, которую затем
сняли с деплоя (#2792). Фактический максимум применённого на main — 239,
то есть весь диапазон 240-249 гейтом не проверяется вообще ("проверено
новых миграций: 0" = не проверено ни одного файла, не "все чисты"). Функция
scan() из самого гейта, прогнанная напрямую без порогового отсечения,
помечает ALTER TABLE в этом файле как блокирующий DDL без lock_timeout.

trade_in_estimates — самая горячая таблица стека (история, история
сотрудников, каждое чтение/PDF оценки); на этой БД уже наблюдались открытые
транзакции на 46 и 22 часа. Ждущая ACCESS EXCLUSIVE-блокировка встаёт в
очередь перед новыми запросами приложения. DDL на 1058 строках мгновенный —
риск не в исполнении, а в ожидании чужой блокировки.

Добавлено SET LOCAL lock_timeout = '5s' сразу после BEGIN + объяснение в
шапке файла, почему оно здесь при том что гейт формально не требует —
чтобы не убрали как "лишнее". Порог гейта не трогаю — отдельный issue.
This commit is contained in:
bot-backend 2026-08-07 15:59:28 +03:00
parent 7431615415
commit 5ce95a28a8

View file

@ -48,9 +48,29 @@
-- строки со строкой в payments опосредованно через predicate purge-джобы,
-- сама таблица payments здесь не читается).
-- Apply after: 233_payments.sql.
--
-- ── lock_timeout — выставлен, хотя гейт (scripts/check-migration-lock-timeout.py)
-- этот файл не проверяет ────────────────────────────────────────────────────
-- Порог гейта для tradein (NN >= 250) — артефакт: назначен по номеру аварийной
-- миграции 250, которую затем сняли с деплоя (#2792, 29f10002). Фактический
-- максимум применённого на main — 239, то есть НИ ОДНА миграция в диапазоне
-- 240-249 (этот файл включительно) гейтом не проверяется вообще — "проверено
-- новых миграций: 0" в логе означает "не проверено ни одного файла", а не
-- "все чисты". Сама функция scan() внутри гейта, если прогнать её без
-- порогового отсечения, помечает ALTER TABLE ниже как блокирующий DDL без
-- lock_timeout. `trade_in_estimates` — самая горячая таблица стека (история,
-- история сотрудников, каждое чтение/PDF оценки); на этой БД уже наблюдались
-- открытые транзакции на 46 и 22 часа. Ждущая ACCESS EXCLUSIVE-блокировка
-- встаёт в очередь ПЕРЕД новыми запросами — за ней начинают ждать обычные
-- SELECT приложения (см. `sql.md` § lock_timeout). На 1058 строках сам DDL
-- мгновенный — риск не в исполнении, а в ожидании чужой блокировки. Красный
-- деплой по таймауту — осознанно принятый в проекте размен (честный отказ
-- лучше тихой очереди перед приложением). НЕ убирать как "гейт же не просит".
BEGIN;
SET LOCAL lock_timeout = '5s';
ALTER TABLE trade_in_estimates
ADD COLUMN IF NOT EXISTS retain_until timestamptz;