Содержание
Коротко
На GitHub когда-то падала база не из‑за взлома, а из‑за одной незакрытой транзакции: миграция ждала эксклюзивную блокировку, новые запросы вставали в очередь за ней — и всё «зависло», пока инженер не нашёл «верхнее» соединение. Тот же сценарий легко воспроизвести в Postgres: необработанное исключение в приложении оставляет транзакцию открытой, миграция блокируется, горячая таблица перестаёт отвечать.
Что произошло
Классический сценарий на MySQL: изменение схемы требует эксклюзивной блокировки таблицы, но другая сессия уже читала эту таблицу и не сделала COMMIT. Миграция ждёт. За ней — все новые запросы к той же таблице. Ни deadlock, ни таймаут сами по себе не спасают: цепочка сидит, пока не завершат проблемное соединение.
В Postgres достаточно обычного пользователя приложения. Транзакция начинает SELECT по горячей таблице orders, приложение падает с исключением — ROLLBACK не вызывается. Сессия «в транзакции», хотя запрос уже завершился. Параллельно миграция делает ALTER TABLE и ждёт ACCESS EXCLUSIVE. Все последующие SELECT встают в очередь. Для сервиса, который ждёт быстрых ответов из orders, это простой.
Причина часто в настройке по умолчанию: idle_in_transaction_session_timeout выключен — «висящие» транзакции не обрываются сами.
PlanetScale описывает инструменты для просмотра и завершения соединений в панели и CLI (pscale branch connections), в том числе когда слоты подключений исчерпаны и отладочный SELECT уже не пройти.
Почему это важно
Это не редкий edge case и не прерогатива MySQL. Любая СУБД с блокировками на уровне таблицы/схемы уязвима к «одному плохому соединению». Симптомы выглядят как полный отказ: все запросы падают, метрики приложения красные, а корень — одна сессия без COMMIT/ROLLBACK.
На собеседованиях этот кейс GitHub использовали как проверку системного мышления DBA. В проде его ловят пейджингом в пятницу вечером.
На практике
- В Postgres задайте
idle_in_transaction_session_timeout(разумное значение в миллисекундах) — транзакции без активности закроются автоматически. - В коде приложения: при любом исключении внутри транзакции — явный ROLLBACK или закрытие соединения через пул с корректной очисткой.
- Миграции на горячих таблицах планируйте с учётом блокировок; для MySQL на Vitess/PlanetScale онлайн-ALTER снижает риск длинной эксклюзивной блокировки.
- Держите способ смотреть активные сессии и «кто кого блокирует» до инцидента, не только когда слоты кончились.
- При разборе инцидента различайте три действия: отменить запрос, завершить транзакцию, оборвать соединение — для «зависшего» SELECT без активного запроса часто нужен именно terminate transaction или terminate connection.
Итог
Падение базы из‑за одного необработанного исключения — урок про границы приложения и СУБД. Таймауты idle-транзакций, дисциплина ROLLBACK и нормальный обзор соединений стоят дешевле, чем час простоя горячей таблицы.

