Если после деплоя не применились миграции, новая версия приложения начинает работать со старой схемой базы. В логах появляются ошибки отсутствующего столбца или таблицы, часть страниц возвращает 500, worker падают, а запись данных может выполняться только наполовину.

Не следует сразу запускать все migration вручную на production. Сначала нужно подтвердить версию кода, активную базу и статус миграций, сделать резервную копию и оценить, совместимы ли изменения с уже запущенными экземплярами приложения.

Сначала снизьте влияние

  • Остановите дальнейшее развертывание и автоматическое масштабирование новой версии.
  • Если операции могут повредить данные, временно ограничьте запись или верните совместимую версию кода.
  • Не перезапускайте migration несколько раз без понимания текущего состояния.
  • Сохраните логи deploy, вывод migration command и идентификатор релиза.
  • Сделайте согласованную резервную копию базы перед изменением схемы.
  • Проверьте фоновые worker и cron: они тоже могут использовать новый код.

Подтвердите рассинхронизацию кода и базы

  • Какой commit или release реально обслуживает запросы.
  • Какая версия приложения отображается на каждом экземпляре.
  • Какая база указана в runtime-конфигурации.
  • Какие migration отмечены выполненными.
  • Какие столбцы, индексы и таблицы присутствуют фактически.
  • Есть ли несколько production-баз или read replica.
  • Не остались ли старые worker с другой версией кода.

Ошибка «столбец не найден» может возникать не только из-за непримененной migration. Запрос иногда уходит в другую базу, на отставшую replica или выполняется старым worker после частичного deploy.

Проверьте таблицу истории миграций

Фреймворк обычно хранит список выполненных migration в служебной таблице. Сравните ее с файлами текущего релиза. Важно различать три состояния: файл не запускался, migration помечена выполненной, но схема не соответствует, либо изменение применилось частично и запись истории отсутствует.

  • Последняя выполненная migration совпадает с ожидаемой версией.
  • В репозитории нет переименованных уже примененных файлов.
  • Номера и timestamp миграций уникальны.
  • История не была очищена при восстановлении базы.
  • Один и тот же релиз не использует разные каталоги migration.
  • Схема проверяется отдельно от служебной отметки.

Убедитесь, что команда запускалась

Deploy может завершиться успешно, хотя шаг миграции был пропущен условием, помечен необязательным или не вошел в pipeline. Просмотрите полный журнал, а не только зеленый статус job.

  • Шаг присутствует в production pipeline.
  • Он не отключен переменной или условием ветки.
  • Команда завершилась с кодом 0, а вывод не был проигнорирован.
  • Скрипт использовал текущий release directory.
  • Ошибка migration прерывает deploy, а не скрывается через continue или конструкцию, всегда возвращающую успех.
  • Timeout CI не оборвал процесс после частичного выполнения.

Сравните окружение CLI и веб-приложения

Частая причина — migration command запускается из shell с другим набором переменных, пользователем, PHP или конфигурационным файлом. В результате команда работает с тестовой базой либо не видит production-секрет.

  • DB host, port, database и user совпадают с runtime приложения.
  • CLI использует нужную версию PHP, Python, Node или другого runtime.
  • Текущая рабочая директория указывает на новый релиз.
  • Переменные окружения загружены тем же безопасным способом.
  • Пользователь deploy имеет права на изменение схемы.
  • Кеш конфигурации не содержит параметры предыдущего окружения.
  • Секреты не выводятся в deploy log.

Проверьте права пользователя базы

Приложение может читать и записывать данные, но не иметь права ALTER, CREATE INDEX или CREATE TABLE. Это хороший принцип минимальных прав, однако для migration нужен отдельный контролируемый пользователь или временно выдаваемое разрешение.

Не запускайте миграции от root базы без необходимости и не храните привилегированный пароль в репозитории. Отдельный deploy-credential должен быть доступен только pipeline и ротироваться по правилам проекта.

Ищите блокировки и долгие транзакции

ALTER TABLE и создание индекса могут ждать lock, пока приложение держит транзакцию. Pipeline видит timeout, а изменение позже завершается или остается частичным в зависимости от СУБД и операции.

  • Активные и ожидающие транзакции.
  • Metadata lock и блокирующий запрос.
  • Размер таблицы и прогноз времени операции.
  • Поддержка online DDL выбранной версией СУБД.
  • Statement timeout и лимит job в CI.
  • Свободное место для перестроения таблицы или индекса.

Не запускайте migration на всех экземплярах

При старте контейнера каждый replica может одновременно попытаться изменить схему. Даже если служебная таблица защищает часть операций, тяжелые DDL и пользовательские скрипты могут конфликтовать.

  • Migration выполняет один выделенный job.
  • Используется lock, поддерживаемый фреймворком или инфраструктурой.
  • Web и worker запускаются после проверенного этапа схемы.
  • Повтор команды безопасен и не создает дубли данных.
  • Deploy не считает приложение готовым до health check схемы.

Оцените совместимость старого и нового кода

Во время rolling deploy старая и новая версии работают одновременно. Migration должна быть совместима с обеими. Удаление или переименование столбца в том же релизе может сломать старые экземпляры.

Expand

  • Добавить новый nullable столбец или таблицу.
  • Создать индекс безопасным для production способом.
  • Развернуть код, который умеет работать со старой и новой схемой.
  • Заполнить данные отдельной контролируемой задачей.

Contract

  • Переключить чтение и запись на новую структуру.
  • Убедиться, что старый код больше не работает.
  • Проверить метрики и данные.
  • В следующем релизе удалить старый столбец или ограничение.

Не смешивайте DDL и большой backfill

Migration, которая добавляет столбец и сразу обновляет миллионы строк, может заблокировать таблицу и превысить timeout. Схему лучше изменить отдельно, а данные переносить пакетами с checkpoint, мониторингом и возможностью продолжить.

  • Пакеты ограничены по размеру и времени.
  • Обработка идемпотентна.
  • Прогресс и ошибки записываются.
  • Нагрузка контролируется.
  • Новый код понимает частично заполненное состояние.
  • Окончательное ограничение NOT NULL добавляется после проверки.

Если migration применена частично

Не все СУБД выполняют DDL транзакционно. Файл мог создать таблицу, затем упасть на индексе и не записаться в историю. Повторный запуск получит ошибку «уже существует».

  1. Остановить автоматические повторные запуски.
  2. Сравнить фактическую схему с каждым шагом migration.
  3. Проверить данные, индексы, ограничения и служебную историю.
  4. Подготовить отдельный repair-план для недостающих частей.
  5. Протестировать его на копии production.
  6. Выполнить исправление с резервной копией и журналом.
  7. Синхронизировать migration history только после подтверждения схемы.

Не отмечайте migration выполненной вручную только ради зеленого статуса. Сначала убедитесь, что все ожидаемые изменения действительно присутствуют.

Как безопасно применить пропущенные миграции

  1. Определить точный release и список pending migration.
  2. Проверить команды на staging с копией структуры и реалистичным объемом.
  3. Сделать и проверить резервную копию production.
  4. Оценить lock, длительность и свободное место.
  5. Остановить конфликтующий deploy и назначить одного runner.
  6. При необходимости ограничить запись или включить maintenance mode.
  7. Запустить migration из правильного release и окружения.
  8. Проверить фактическую схему и служебную историю.
  9. Запустить smoke tests веба, API, worker и cron.
  10. Только после этого продолжить deploy.

Откат кода не всегда откатывает базу

Если новая migration уже изменила или удалила данные, возврат старого контейнера не восстановит схему. Down migration тоже не всегда безопасна: она может удалить новый столбец вместе с уже записанными значениями.

  • Предпочитайте forward fix для обратимо расширенной схемы.
  • Проверяйте совместимость старого кода до rollback.
  • Деструктивные операции выполняйте отдельным поздним релизом.
  • Восстановление из backup используйте по согласованному плану с учетом новых данных.
  • Не обещайте мгновенный rollback без проверки состояния базы.

Добавьте preflight и post-deploy проверки

  • Доступность базы и версия СУБД.
  • Наличие нужных прав deploy-user.
  • Список pending migration.
  • Свободное место и отсутствие опасной блокировки.
  • Соответствие app version и schema version.
  • Работа ключевых чтений и записей после deploy.
  • Готовность worker и отсутствие роста ошибок.

Pipeline должен завершаться ошибкой, если migration не прошла. Нельзя переводить трафик на новую версию только потому, что контейнер отвечает на простой health endpoint.

Как проверить исправление

  • Pending migration отсутствуют.
  • Фактическая схема совпадает с ожидаемой.
  • Каждый экземпляр работает на одной согласованной версии.
  • Web, API, worker и cron используют одну production-базу.
  • Создание и обновление данных проходит smoke test.
  • Ошибки отсутствующих столбцов и таблиц перестали появляться.
  • Backfill завершен и проверен по количеству и выборке.
  • Rollback или forward-fix план обновлен по итогам инцидента.

Типичные ошибки

  • Запустить все migration вручную без backup.
  • Использовать CLI с конфигурацией тестовой базы.
  • Игнорировать ненулевой exit code в pipeline.
  • Запускать migration при старте каждого контейнера.
  • Переименовывать примененные migration-файлы.
  • Объединять тяжелый backfill и DDL в одну транзакцию релиза.
  • Удалять старый столбец до завершения rolling deploy.
  • Отмечать migration выполненной без проверки схемы.
  • Считать откат кода полным откатом базы.

Профилактика

Версия схемы должна быть частью релиза и наблюдаемого состояния приложения. Тестируйте migration на копии структуры, измеряйте тяжелые операции, используйте один runner, expand–contract и автоматический smoke test после изменения базы.

Итог

Когда после деплоя не применились миграции, нужно подтвердить реальную базу, окружение CLI, историю и фактическую схему, а затем безопасно выполнить только недостающие изменения. Порядок deploy, один migration runner и совместимая схема предотвращают повторение сбоя.

Если нужно восстановить такой релиз, я могу проверить pipeline, окружение и состояние базы, подготовить безопасное применение или repair migration, настроить expand–contract, проверки версии схемы, резервное копирование и остановку deploy при ошибке.