[Перевод] Наводим порядок в наших миграциях

be016a57152d43aca6d548dd95d20a33.jpeg

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

Сегодня же я хочу поделиться с вами советом, который поможет навести порядок в ваших миграциях… если вы обнаружили, что ваш каталог migrations/ разросся до каких-то немыслимых масштабов… как это случилось с нами! Конечно, стоит оговориться, что это представляет проблему в основном для локальной разработки: на продакшене нас не очень волнует, сколько файлов миграции было выполнено в прошлом.

Но в качестве сетапа для локальной разработки рекомендуется создать отдельную базу данных, а затем выполнить команду doctrine:migrations:migrate, чтобы получить именно то, что мы имеем в продакшене, включая таблицу migration_versions. Это лучше, чем выполнять команду doctrine:schema:update, которая затрудняет тестирование новых миграций.

И если у вас накопилось много старых файлов миграции, это все может выполняться очень долго! На SymfonyCasts у нас их было 49. Поэтому, хотя это совершенно необязательно, если гигантская папка migrations/ начинает доставлять вам неудобства, вы можете навести в ней порядок! Также вас следует поздравит с успешным сайтом, который прожил достаточно долго, чтобы в этом нуждаться.

Генерация полной единой миграции

Tip

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

Прежде всего, удалите все миграции:

rm -rf migrations/

Теперь сбросьте текущую схему в новую единую миграцию:

symfony console doctrine:migrations:dump-schema

Этот пакет предоставляет еще одну команду, которая помогает «свернуть» миграции, удалив все отслеживаемые версии и вставив одну актуальную:

symfony console doctrine:migrations:rollup

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

P.S. Спасибо Кристофу Ковету (Christophe Coevoet) за то, что он указал это в комментариях.

Конечно, сначала мы сделаем это локально, так что запустите:

rm -rf migrations/

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

symfony console doctrine:schema:drop --force

 Tip

Команда symfony console аналогична команде bin/console, но позволяет вводить переменные окружения, если вы используете интеграцию с Docker.

Теперь сгенерируем новую миграцию с помощью MakerBundle:

symfony console make:migration

Как следует проверьте запросы внутри нового файла, чтобы убедиться, что новая миграция выглядит как надо.

Но мы не можем просто закоммитить эти изменения и развернуть их на продакшене… потому что сервер базы данных попытается выполнить эту команду и воссоздать таблицы, которые уже есть на продакшене! Нет ничего менее приятного, чем сбой миграции во время развертывания! Как мы можем обойти эту проблему без ручного вмешательства в базу данных продакшена?

Пропуск повторной миграции на продакшене

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

git status

Например, если раньше файл миграции назывался Version20220415102030.php, переименуйте только что созданный файл миграции именно в это имя и не забудьте соответствующим образом изменить имя класса внутри файла. Это позволит выполнить развертывание в продакшн, но эта миграция не будет выполнена (будет пропущена), поскольку она уже была выполнена в прошлом.

Удаление ранее выполненных миграций из продакшена

Но мы можем еще немного улучшить ситуацию. Ведь если выполнить эту миграцию прямо сейчас, то она будет выдаст что-то вроде этого:

[WARNING] You have X previously executed migrations in the database that are not registered migrations.

Неприятно! Это происходит потому, что таблица migration_versions в продакшене теперь показывает, что в прошлом была выполнена куча миграций…, но эти файлы миграций больше не существуют! Мы могли бы удалить их вручную из базы данных нашего продакшена, но… о ужас! Выполнять вручную запрос DELETE в производственной базе данных менее приятно, чем везти кошку к ветеринару.

Вместо этого сгенерируйте пустую миграцию:

symfony console doctrine:migration:generate

Затем откройте ее и добавьте в конец новый SQL-оператор:

final class Version20220415102031 extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        // данная миграция генерируется автоматически, пожалуйста, измените ее в соответствии с вашими потребностями

        $this->addSql('DELETE FROM migration_versions WHERE version NOT LIKE "%20220415102030" AND version NOT LIKE "%20220415102031"');
    }

    // ...
}

Где 20220415102031 — номер пустой миграции, которую мы только что сгенерировали, а 20220415102030 — номер другой полной миграции, которую мы имеем. Убедитесь, что вы заменили эти номера на свои!

И все готово! Попробуйте сначала локально:

symfony console doctrine:migration:migrate

Предупреждение все равно будет показано, но только один раз. Чтобы перепроверить, можно посмотреть таблицу migration_versions в локальной базе данных и убедиться, что в ней присутствуют только эти 2 миграции.

Теперь можно смело развертывать это в продакшене и радоваться чистому каталогу migrations/!

Всех желающих приглашаем на открытый урок «Kafka. Используем в Symfony», на которомрассмотрим использование альтернативы RabbitMQ в Symfony-приложениях. Обсудим преимущества и недостатки. Записаться можно на странице курса «Symfony Framework».

© Habrahabr.ru