revert(tradein/db): снять 250 с деплоя — очередь за локом блокирует пайплайн #2792

Merged
bot-backend merged 1 commit from revert/250-unblock-deploy into main 2026-08-07 11:01:32 +00:00
Collaborator

Зачем

Пайплайн trade-in закрыт: четыре прогона деплоя подряд красные на 250_drop_duplicate_expires_at_index.sql. DROP INDEX ждёт ACCESS EXCLUSIVE за чужой ручной аналитической сессией (pid 83256, CREATE TEMP TABLE tmp_res AS ..., идёт 1 ч 33 мин, конца не видно); две попытки ждали 29 и 16 минут и были сняты вручную. Контейнер tradein-backend собран в 09:25 UTC — четыре смерженных после этого PR (#2785, #2789 и др.) до прода не доехали. Блокирует не логика, а очередь.

Вдобавок ждущий ACCESS EXCLUSIVE встаёт в очередь перед новыми запросами: за ним начали бы ждать и обычные SELECT приложения. Пока обошлось, но цена ошибки выше выигрыша — снос дубля даёт 48 КБ и ничего операционно.

Почему откат безопасен

Миграция не применена ни на проде, ни где-либо ещё — проверено на боевой БД 2026-08-07 13:56 MSK:

SELECT count(*) FROM _schema_migrations
 WHERE filename='250_drop_duplicate_expires_at_index.sql';  →  0

последние применённые: 238 (09:25 UTC), 239 (09:14 UTC)
оба индекса на месте: trade_in_estimates_expires_idx (234 скана),
                      trade_in_estimates_expires_at_idx (18)

Коммит #2784 добавил ровно один файл и ничего больше — удаление файла и есть полный откат, БД не трогается. Файла нет в _manifest_applied.txt, поэтому инвариант #2216 (нельзя удалять применённые имена) не задет — гейт test_manifest_entries_all_exist останется зелёным.

Что дальше

  1. Мерж → деплой проходит цикл миграций без 250 → четыре застрявших PR доезжают до прода.
  2. Конвенция lock_timeout + гейт + проверка невалидных индексов — в #2791 (там же разбор, почему SET LOCAL доживает до DROP в этом раннере и почему нельзя задать lock_timeout глобально).
  3. Сам снос дубля вернуть отдельным PR с SET LOCAL lock_timeout = '5s', когда таблица тиха. Критерий «тиха» (записан заранее): SELECT count(*) FROM pg_locks l JOIN pg_class c ON c.oid=l.relation WHERE c.relname='trade_in_estimates' AND l.pid <> pg_backend_pid(); → 0.

Чужую сессию 83256 не трогали — это чужая работа на полтора часа.

Test plan

  • _schema_migrations на проде не содержит 250 (запрос выше)
  • файла нет в _manifest_applied.txt → манифест-гейт не краснеет
  • коммит #2784 добавил только этот файл (git show --stat)
  • после мержа: деплой зелёный и docker ps показывает пересобранный tradein-backend

Refs #2752

## Зачем Пайплайн trade-in закрыт: четыре прогона деплоя подряд красные на `250_drop_duplicate_expires_at_index.sql`. `DROP INDEX` ждёт `ACCESS EXCLUSIVE` за чужой ручной аналитической сессией (pid 83256, `CREATE TEMP TABLE tmp_res AS ...`, идёт **1 ч 33 мин**, конца не видно); две попытки ждали 29 и 16 минут и были сняты вручную. Контейнер `tradein-backend` собран в 09:25 UTC — **четыре смерженных после этого PR (#2785, #2789 и др.) до прода не доехали**. Блокирует не логика, а очередь. Вдобавок ждущий `ACCESS EXCLUSIVE` встаёт в очередь **перед новыми запросами**: за ним начали бы ждать и обычные SELECT приложения. Пока обошлось, но цена ошибки выше выигрыша — снос дубля даёт 48 КБ и ничего операционно. ## Почему откат безопасен Миграция **не применена ни на проде, ни где-либо ещё** — проверено на боевой БД 2026-08-07 13:56 MSK: ``` SELECT count(*) FROM _schema_migrations WHERE filename='250_drop_duplicate_expires_at_index.sql'; → 0 последние применённые: 238 (09:25 UTC), 239 (09:14 UTC) оба индекса на месте: trade_in_estimates_expires_idx (234 скана), trade_in_estimates_expires_at_idx (18) ``` Коммит #2784 добавил ровно один файл и ничего больше — удаление файла и есть полный откат, БД не трогается. Файла нет в `_manifest_applied.txt`, поэтому инвариант #2216 (нельзя удалять применённые имена) не задет — гейт `test_manifest_entries_all_exist` останется зелёным. ## Что дальше 1. Мерж → деплой проходит цикл миграций без 250 → четыре застрявших PR доезжают до прода. 2. Конвенция `lock_timeout` + гейт + проверка невалидных индексов — в #2791 (там же разбор, почему `SET LOCAL` доживает до DROP в этом раннере и почему нельзя задать `lock_timeout` глобально). 3. Сам снос дубля вернуть отдельным PR **с** `SET LOCAL lock_timeout = '5s'`, когда таблица тиха. Критерий «тиха» (записан заранее): `SELECT count(*) FROM pg_locks l JOIN pg_class c ON c.oid=l.relation WHERE c.relname='trade_in_estimates' AND l.pid <> pg_backend_pid();` → 0. **Чужую сессию 83256 не трогали** — это чужая работа на полтора часа. ## Test plan - [x] `_schema_migrations` на проде не содержит 250 (запрос выше) - [x] файла нет в `_manifest_applied.txt` → манифест-гейт не краснеет - [x] коммит #2784 добавил только этот файл (`git show --stat`) - [ ] после мержа: деплой зелёный и `docker ps` показывает пересобранный `tradein-backend` Refs #2752
bot-backend added 1 commit 2026-08-07 10:57:01 +00:00
revert(tradein/db): снять 250 с деплоя — очередь за локом блокирует пайплайн
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m47s
81db46c736
Миграция (#2784) на проде НЕ применена: записи в _schema_migrations нет
(проверено 2026-08-07 13:56 MSK, последние применённые — 238 и 239). БД не
изменена, оба индекса на месте, откат возвращает ровно прежнее состояние.

Почему сейчас: DROP INDEX ждёт ACCESS EXCLUSIVE за чужой ручной аналитической
сессией (pid 83256, CREATE TEMP TABLE ... , идёт 1 ч 33 мин, конца не видно).
Четыре прогона деплоя подряд красные на этой миграции, ждали 29 и 16 минут.
Пайплайн заблокирован не логикой, а очередью: контейнер tradein-backend собран
в 09:25 UTC, четыре смерженных после этого PR (#2785, #2789 и др.) до прода не
доехали.

Ждущий ACCESS EXCLUSIVE встаёт в очередь ПЕРЕД новыми запросами, поэтому за ним
начали бы ждать и обычные SELECT приложения — цена ошибки выше, чем выигрыш.

Цена отката нулевая: снос дубля освобождает 48 КБ и ничего операционно. Вернём
отдельным PR с `SET LOCAL lock_timeout` (см. #2791), когда таблица тиха.
Файла нет в _manifest_applied.txt, поэтому инвариант #2216 не задет.

Refs #2752
bot-backend merged commit 29f1000228 into main 2026-08-07 11:01:32 +00:00
bot-backend deleted branch revert/250-unblock-deploy 2026-08-07 11:01:32 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2792
No description provided.