Копии и выкат

Код или миграция первым: порядок, который зависит от направления

Правило одно и оно несимметрично. Сносите колонку — сначала выкат, потом миграция. Добавляете — наоборот. Ошибка порядка даёт несколько минут сломанного экрана на бою.

Александр Цапков10 сентября 20262 мин

Вопрос «что катить первым — код или миграцию» звучит как дело вкуса. Это не так: у него есть правильный ответ, и он разный в разные стороны.

Правило

Сносите колонку, которую читает старый код — сначала выкат, потом миграция.

Добавляете колонку, которую читает новый код — сначала миграция, потом выкат.

Оба случая сводятся к одному вопросу: какая из двух половин переживёт момент, когда вторая уже изменилась, а первая ещё нет.

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

Что происходит при ошибке

Между накатом и выкатом всегда есть промежуток: минута, две, пять — сколько собирается образ и перезапускается контейнер.

Ошибётесь направлением — в этом промежутке работающий на бою код обращается к тому, чего уже нет. Это не падение сборки и не красный тест: всё собралось, всё выкатилось, просто несколько минут часть экранов отвечала ошибкой. Заметит это клиент, а не вы.

Переименование — это не одно изменение

Самая частая ловушка. ALTER TABLE ... RENAME COLUMN кажется одной операцией, но для приложения это одновременно и удаление, и добавление — то есть оба направления сразу, и безопасного порядка не существует.

Разворачивается это в три шага, каждый со своим выкатом:

  1. добавить новую колонку, писать в обе, читать из старой;
  2. перелить данные, переключить чтение на новую;
  3. убрать старую колонку и запись в неё.

Дольше и скучнее — зато ни в один момент нет состояния, в котором код и схема не совместимы.

Порядок наката, который мы держим

Миграции применяются раннером и от роли, у которой есть права на изменяемые объекты, — под обычной ролью получите «must be owner of table» и потеряете время на ложный след.

Сам порядок всегда один:

status → холостой прогон → накат → проверка состояния запросом

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

Как проверить себя перед выкатом

Один вопрос, который отвечает на всё: если сейчас пройдёт только одна из двух частей — код или миграция, — что сломается?

Если ответ «ничего» — порядок правильный. Если «часть экранов» — вы держите в руках вторую половину и катите её первой.


Мы выкатываем на серверы клиентов, и там этот промежуток так же реален, как у себя. Поэтому выкат у нас переключает трафик только после проверки здоровья, а не по факту запуска. Как это устроено — Деплой из Git.

Деплой из Git на свои серверыВыкат из git на свои серверы: домены, сертификаты, проверка здоровья, откат одной кнопкой.

Читайте также

Автор

Александр ЦапковОснователь Скоупворк

Веду платформу и её боевой контур сам: разработка, выкат, дежурство. Пишу о том, на чём мы обожглись, — с датами, замерами и ссылками на решения в репозитории.