|
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m44s
CI / openapi-codegen-check (pull_request) Successful in 2m37s
CI Trade-In / backend-tests (pull_request) Successful in 4m28s
CI / backend-tests (pull_request) Successful in 15m57s
Миграция 250 (DROP INDEX на таблице в 1061 строку) 2026-08-07 встала на боевой БД: сам DROP берёт лок за миллисекунды, но ЖДАЛ его выдачи 29 минут за чужой аналитической psql-сессией, вторая попытка деплоя — ещё 16. Записи в _schema_migrations нет, схема не изменена — следующий деплой упёрся бы так же. Опасность не в простое деплоя: ждущий ACCESS EXCLUSIVE встаёт в очередь ПЕРЕД новыми запросами, поэтому за ним начинают ждать обычные SELECT приложения. - 250: SET LOCAL lock_timeout = '5s' сразу после BEGIN. Значение не наугад: снизу ограничено deadlock_timeout (1 s на проде) — автоотмена мешающего autovacuum срабатывает только после того, как ждущий отстоял эту секунду, так что 1-2 s гонялись бы с рутинным autovacuum; сверху 5 s — потолок простоя очереди приложения, против наблюдённых 1740 s это в 348 раз меньше. Проверено в форме запуска раннера (psql < файл, PostgreSQL 16.4, встречная сессия держит ACCESS SHARE): со строкой — отказ через 5 s и exit 3, без неё команда всё ещё висела в очереди на 15-й секунде. SET LOCAL доживает до DROP потому, что файл идёт одной psql-сессией и весь завёрнут в BEGIN/COMMIT. - scripts/check-migration-lock-timeout.py + шаг в ci.yml: новая миграция с блокирующим DDL обязана нести SET LOCAL lock_timeout, внутри транзакции и ДО первого DDL. Гейт бежит на каждом PR (обоих лэйнов), у него --selftest. Вариант «задать lock_timeout один раз в раннере» отвергнут замером, а не вкусом: session-wide значение обрывает CREATE INDEX CONCURRENTLY (тот ждёт параллельные транзакции через VirtualXactLock, и это ожидание тоже под lock_timeout) и оставляет невалидный индекс — то есть изготавливало бы ровно ту аварию, от которой заведена вторая проверка. Блокирующий DDL и CONCURRENTLY хотят противоположной политики → granularity = файл. - deploy.yml / deploy-tradein.yml: после цикла миграций — отказ, если в БД есть индексы с indisvalid=false (#2752). Оборванный CIC оставляет такой индекс молча: планировщик им не пользуется, а re-run миграции не чинит — CREATE INDEX CONCURRENTLY IF NOT EXISTS печатает «already exists, skipping» и выходит с кодом 0, после чего миграция помечается применённой. На проде таких индексов сейчас 0 (обе БД) — это профилактика. Refs #2752 |
||
|---|---|---|
| .. | ||
| auth | ||
| claude-hooks | ||
| bootstrap_glitchtip.sh | ||
| bootstrap_schema_migrations.sh | ||
| build_osrm.sh | ||
| check-migration-lock-timeout.py | ||
| check-workflow-ports.py | ||
| cleanup-merged-worktrees.sh | ||
| cleanup-stale-claims.sh | ||
| cleanup-worktrees-aggressive.py | ||
| cleanup_ghosts.py | ||
| migrate_kg_to_obsidian.py | ||
| setup-bot-env.ps1 | ||
| setup-couchdb.sh | ||
| smoke-mera-perimeter.sh | ||
| start-analyst.ps1 | ||
| start-backend.ps1 | ||
| start-bot.ps1 | ||
| start-frontend.ps1 | ||
| start-qa.ps1 | ||
| start-reviewer.ps1 | ||