Код или миграция первым: порядок, который зависит от направления
Правило одно и оно несимметрично. Сносите колонку — сначала выкат, потом миграция. Добавляете — наоборот. Ошибка порядка даёт несколько минут сломанного экрана на бою.
Вопрос «что катить первым — код или миграцию» звучит как дело вкуса. Это не так: у него есть правильный ответ, и он разный в разные стороны.
Правило
Сносите колонку, которую читает старый код — сначала выкат, потом миграция.
Добавляете колонку, которую читает новый код — сначала миграция, потом выкат.
Оба случая сводятся к одному вопросу: какая из двух половин переживёт момент, когда вторая уже изменилась, а первая ещё нет.
| Что делаете | Первым | Почему |
|---|---|---|
| удаляете колонку | код | пока миграция не прошла, старый код ещё читает колонку — и она на месте |
| добавляете колонку | миграция | пока код не выкачен, новую колонку никто не читает — она просто есть |
| переименовываете | ни то ни другое | это два изменения, а не одно, — см. ниже |
Что происходит при ошибке
Между накатом и выкатом всегда есть промежуток: минута, две, пять — сколько собирается образ и перезапускается контейнер.
Ошибётесь направлением — в этом промежутке работающий на бою код обращается к тому, чего уже нет. Это не падение сборки и не красный тест: всё собралось, всё выкатилось, просто несколько минут часть экранов отвечала ошибкой. Заметит это клиент, а не вы.
Переименование — это не одно изменение
Самая частая ловушка. ALTER TABLE ... RENAME COLUMN кажется одной операцией,
но для приложения это одновременно и удаление, и добавление — то есть оба
направления сразу, и безопасного порядка не существует.
Разворачивается это в три шага, каждый со своим выкатом:
- добавить новую колонку, писать в обе, читать из старой;
- перелить данные, переключить чтение на новую;
- убрать старую колонку и запись в неё.
Дольше и скучнее — зато ни в один момент нет состояния, в котором код и схема не совместимы.
Порядок наката, который мы держим
Миграции применяются раннером и от роли, у которой есть права на изменяемые объекты, — под обычной ролью получите «must be owner of table» и потеряете время на ложный след.
Сам порядок всегда один:
status → холостой прогон → накат → проверка состояния запросом
Последний шаг важнее, чем кажется: состояние миграций читается из базы, а не из вывода команды. Вывод говорит, что раннер собирался сделать. База говорит, что получилось.
Как проверить себя перед выкатом
Один вопрос, который отвечает на всё: если сейчас пройдёт только одна из двух частей — код или миграция, — что сломается?
Если ответ «ничего» — порядок правильный. Если «часть экранов» — вы держите в руках вторую половину и катите её первой.
Мы выкатываем на серверы клиентов, и там этот промежуток так же реален, как у себя. Поэтому выкат у нас переключает трафик только после проверки здоровья, а не по факту запуска. Как это устроено — Деплой из Git.
Читайте также
- Четыреста тридцать миграций и семь номеров, занятых дваждыНомер выбирают в момент создания файла, а применяют через день. Две ветки берут один свободный номер, и коллизия всплывает не у автора, а на чужой машине при накате.
- Два запроса в окно выката: почему 5xx на robots.txt дороже, чем на страницеЗа сутки 157 успешных ответов и два ответа 502 — оба в одну секунду, в момент перезапуска контейнера. Поисковик читает 5xx на robots.txt как «обход запрещён» и ставит краулинг на паузу.
Автор
Александр ЦапковОснователь Скоупворк
Веду платформу и её боевой контур сам: разработка, выкат, дежурство. Пишу о том, на чём мы обожглись, — с датами, замерами и ссылками на решения в репозитории.