From 5ce95a28a864a2327df83d5f985636c09fbf365b Mon Sep 17 00:00:00 2001 From: bot-backend Date: Fri, 7 Aug 2026 15:59:28 +0300 Subject: [PATCH] =?UTF-8?q?fix(tradein/payments):=20SET=20LOCAL=20lock=5Ft?= =?UTF-8?q?imeout=20=D0=B2=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20240=20(gate=20threshold=20=E2=80=94=20=D0=B0=D1=80?= =?UTF-8?q?=D1=82=D0=B5=D1=84=D0=B0=D0=BA=D1=82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../240_trade_in_estimates_retain_until.sql | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tradein-mvp/backend/data/sql/240_trade_in_estimates_retain_until.sql b/tradein-mvp/backend/data/sql/240_trade_in_estimates_retain_until.sql index 93693455..e9b0cb67 100644 --- a/tradein-mvp/backend/data/sql/240_trade_in_estimates_retain_until.sql +++ b/tradein-mvp/backend/data/sql/240_trade_in_estimates_retain_until.sql @@ -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;