Выкатите релиз и проведите его через наблюдение
Чек-лист деплоя: мерж, деплой, канарейка, верификация. Используйте при развёртывании в продакшен, чтобы не пропустить критичные шаги.
Как агент работает
Перед выкаткой навык задаёт шесть вопросов: что именно едет — тег или диапазон коммитов вроде a887c26..982e407, меняется ли схема БД, проставлены ли новые переменные окружения и ключи коннекторов в проде до кода, что произойдёт с воркером, получившим SIGTERM посреди задачи, обратима ли выкатка вообще и кто на связи ближайшие два часа. Нет ответа на первый, второй или пятый вопрос — выкатка не готова, и это вердикт, а не пожелание.
Стратегия выбирается не по уровню осторожности, а по требованиям к приложению. Прямая замена — единственный момент, когда работает ровно одна версия, и только здесь безопасно катится схема, несовместимая с прошлым кодом. Rolling требует, чтобы версии N и N+1 жили с одной схемой и одним форматом сообщений в очередях, и согласования maxSurge с пулом коннектов. Blue-green даёт откат за секунды ценой двойной ёмкости, а канарейка 1% — 10% — 50% — 100% с паузами 15 минут, 30 минут и час имеет смысл только выше примерно 500 запросов в минуту.
Схема БД едет отдельным событием раньше кода и обязана быть совместима со старым кодом: экспансия — миграция — сжатие, где удаление старого поля ждёт релиза, после которого откат на версию, читающую это поле, уже не нужен. CREATE INDEX идёт CONCURRENTLY, SET NOT NULL — через CHECK ... NOT VALID и VALIDATE CONSTRAINT, внешний ключ добавляется NOT VALID и валидируется отдельным шагом, а backfill идёт пачками по 5-50 тысяч строк. Строка lock_timeout — главная в любой миграции: без неё ALTER TABLE не падает, а копит за собой очередь из обычных SELECT.
После выкатки навык держит пять сигналов — долю ошибок, задержку p95 или p99 вместо среднего, насыщение, поток запросов и новые строки в логах — плюс один бизнесовый счётчик в сравнении с тем же часом прошлой недели. Горизонты разные: 0-5 минут ловят рестарты и отсутствующие переменные, 5-30 минут — регрессии на реальном трафике, 30 минут - 2 часа — утечки памяти и исчерпание пулов, первые сутки — ночные задания и тихо неверные расчёты. Порог отката: 5xx впятеро выше базовой, p95 +100%, цикл рестартов, бизнес-счётчик минус 50%.
Названия метрик и дашбордов клиента навык не выдумывает: спрашивает, где они лежат, или работает по логам. И он не берётся отменить то, что откату не поддаётся — отправленные письма, пуши и СМС, проведённые платежи и фискальные чеки, документы в 1С, цены и остатки, уже принятые Ozon и Wildberries. Для таких релизов до выкатки пишется компенсация: каким запросом найти пострадавшие записи, как их исправить и что сказать затронутым людям.
1. Шесть вопросов до нажатия кнопки
- Что именно едет? Тег или диапазон коммитов:
v1.8.377,a887c26..982e407. «Предыдущая версия» не адрес, и откатывать будет нечего. - Меняется ли схема БД? Если да — схема и код это две отдельные выкатки (раздел 3), самый частый источник невозможного отката.
- Новые переменные окружения, секреты, ключи коннекторов? Проставлены ли в проде до кода: приложение, падающее на старте из-за отсутствующего
YOOKASSA_SHOP_ID, уходит в цикл рестартов и роняет группу под rolling. - Что с текущими соединениями? Воркер, получивший SIGTERM посреди задачи и не умеющий вернуть её в очередь, теряет работу пользователей молча.
- Обратима ли выкатка вообще? См. 6.4: рассылка, списание, необратимая миграция — план восстановления пишется до, а не после.
- Кто на связи ближайшие 2 часа и подходящий ли сейчас час? Не «команда уведомлена», а человек с правами на откат; про час — раздел 7.
Нет ответа на 1, 2 или 5 — выкатка не готова. Это вердикт, а не пожелание.
2. Стратегии: выбирай не по риску, а по требованиям к приложению
Стратегия — не уровень осторожности, а набор требований. Стратегия, требований которой приложение не выполняет, риск не снижает, а добавляет новый.
2.1 Прямая замена
Простой равен времени старта и прогрева. Взамен — единственный момент, когда работает ровно одна версия: только здесь можно безопасно катить схему, несовместимую с прошлым кодом.
2.2 Rolling update
Требует главного и почти всегда забываемого: версии N и N+1 должны одновременно работать с одной схемой БД и одним форматом сообщений в очередях — это ограничение важнее самой стратегии. Новая версия читает колонку, которой ещё нет, — половина запросов падает всю раскатку. Новая версия кладёт в очередь новый формат, старый консьюмер его не разбирает — задачи теряются, и потеря не видна в HTTP-метриках.
Требует также readiness-пробы, graceful-периода больше самого долгого запроса и согласования maxSurge с пулом коннектов: 10 подов × 20 коннектов при maxSurge: 100% дают 400 вместо 200 — лимит Postgres упрётся на середине выкатки.
2.3 Blue-green
Полная вторая среда, переключение одним движением, старая остаётся живой — откат за секунды. Требует двойной ёмкости на время переключения (в российском облаке это прямые деньги — посчитай) и решённого вопроса про БД: общая возвращает вас к требованию 2.2, отдельная означает, что записанное после переключения при откате потеряется без обратной репликации.
2.4 Канареечная
1% → 10% → 50% → 100% с паузами 15 мин / 30 мин / 1 час; для релизов, меняющих расчёты, паузы удлиняй — такие ошибки видны не в 5xx, а в жалобах.
Требует того, о чём вспоминают последним: трафика, при котором 1% что-то значит. При 20 запросах в минуту 1% — это три запроса за 15-минутную ступень, то есть гадание, а не эксперимент; ниже примерно 500 запросов в минуту суммарно начинай с 10%. Требует также липкости сессии (иначе человек увидит два поведения подряд и принесёт баг, который не воспроизводится) и раздельных метрик по версиям: без разделения 1% ошибок утонет в 99% нормы.
2.5 Выбор
| Ситуация | Стратегия |
|---|---|
| Текст, конфиг, стили | Прямая или rolling — цена ошибки ниже цены церемонии |
| Обычная фича, схема не менялась | Rolling |
| Схема поменялась несовместимо | Прямая, в окно простоя: единственный момент, когда версия одна |
| Деньги, платежи, начисления | Blue-green: откат должен занимать секунды |
| Крупная фича, трафик есть | Канареечная: ошибка достанется 1%, а не всем |
| Крупная фича, трафика мало | Rolling + фича-флаг: долю задаёт флаг, а не роутер |
3. Схема БД едет отдельно от кода
3.1 Почему отдельно
Код откатывается за минуту — старый образ никуда не делся. Схема не откатывается полностью никогда: данные, записанные новой версией, уже есть, а DROP COLUMN уничтожает их безвозвратно. Пока схема и код едут одной кнопкой, откат кода означает откат схемы, а откат схемы — потерю данных.
Выкатка схемы — отдельное событие раньше кода, и схема обязана быть совместима со старым кодом. Тогда откатывать нечего, кроме кода.
3.2 Экспансия — миграция — сжатие
Экспансия — добавь новое, не удаляя старого: колонка nullable или с константным дефолтом, таблица, индекс. Старый код работает, потому что про новое не знает.
Миграция — код пишет в оба места и читает из нового с падением обратно на старое; параллельно идёт backfill истории.
Сжатие — код перестаёт писать в старое место, и отдельным релизом, не раньше, чем исчезнет нужда откатываться на версию, читающую старое поле, старое удаляется. Здесь торопятся и получают невозможный откат.
RENAME COLUMN мгновенен и выглядит невинно, но несовместим с любой стратегией без простоя: переименование — три релиза.
3.3 Что блокирует таблицу в Postgres и как обойти
Этот список важнее знания стратегий: блокировка на горячей таблице кладёт сервис целиком, а не частично.
| Операция | Что делает | Обход |
|---|---|---|
CREATE INDEX | Блокирует запись на всё время построения | CONCURRENTLY: дольше, вне транзакции, при сбое оставляет невалидный индекс — удалить и повторить |
ADD COLUMN с volatile-дефолтом (now(), gen_random_uuid()) | Переписывает таблицу | Nullable → заполнить пачками → поставить дефолт |
ADD COLUMN с константным дефолтом | В современном Postgres быстро, без переписывания | Можно напрямую, сверившись с версией сервера |
SET NOT NULL | Полный скан под тяжёлой блокировкой | CHECK (col IS NOT NULL) NOT VALID → VALIDATE CONSTRAINT → SET NOT NULL примет уже проверенный CHECK |
ADD FOREIGN KEY | Блокирует обе таблицы на время проверки | NOT VALID, затем отдельным шагом VALIDATE |
ALTER COLUMN TYPE | Переписывает таблицу и индексы | Новая колонка + зеркалирование + переключение; расширение varchar вверх — дешёвое исключение |
DROP COLUMN | Мгновенно, но данные недоступны | Опасность не в блокировке: старый код с SELECT * и колонкой в ORM-модели упадёт после отката |
В MySQL логика та же, инструмент другой: ALGORITHM=INPLACE, LOCK=NONE, а где он не поддерживается — gh-ost или pt-online-schema-change.
3.4 lock_timeout — главная строчка любой миграции
ALTER TABLE, ждущий тяжёлой блокировки, встаёт в очередь, и всё, что приходит после, встаёт за ним — включая обычные SELECT. Один долгий отчёт плюс ваш ALTER — и сервис лежит целиком, хотя таблица «просто добавляла колонку».
Не удалось — миграция падает быстро и безвредно, повторяете через минуту. Без lock_timeout она не падает, а ждёт, собирая за собой очередь.
3.5 Долгий backfill
Backfill — не миграция, а фоновая работа: единый UPDATE на миллионы строк держит транзакцию часами, раздувает WAL, блокирует автовакуум и при обрыве откатывает всё. Пачками по первичному ключу (5–50 тыс. строк, чтобы пачка укладывалась в секунду-две), с паузой между пачками, с курсором в отдельной таблице для возобновляемости, отдельной задачей — миграция обязана завершаться за секунды. Признаки, что идёт не так: растёт лаг реплики, растут n_dead_tup, растёт WAL-каталог; лаг перевалил единицы секунд — увеличивай паузу, а не размер пачки.
3.6 Почему откат схемы не симметричен
ADD COLUMN обратим ценой всего, что в колонку записали; разбиение колонки — только если склейка однозначна; нормализация справочника необратима, если схлопнули дубликаты; смена типа обратима, только если не терялась точность.
4. Фича-флаг вместо отката
Откат отменяет весь релиз: сломалось одно изменение из десяти — уезжают и девять исправных, а флаг выключает одно. Флаг ещё и отделяет момент выкатки от момента включения: код едет в спокойное окно, фича включается в понедельник утром, когда все на месте. Фича, видимая пользователю и выключаемая строчкой конфига, едет за флагом — особенно изменения в расчётах: формула комиссии, алгоритм подбора, логика начисления.
Правила: у флага есть владелец и срок жизни, а удаление планируется тем же релизом, что и включение на 100% (флаг старше пары месяцев — мёртвая ветка, которую никто не тестирует); флаг проверяется в одном месте, а не в сорока, иначе выключение оставит систему в состоянии, которого не было ни до, ни после; аварийное выключение отдельно от процентного раскатывания; состояние флагов пишется в запись о выкатке. Флаг не откатывает данные: сотня строк в новом формате останется, и старый код должен уметь их прочитать или хотя бы не падать; писем он не отзывает и бесполезен, если ошибка в общем коде обеих ветвей.
5. Наблюдение
5.1 Пять сигналов — и почему именно они
- Доля ошибок (5xx, необработанные исключения, отвалы фоновых задач) — «работает ли вообще».
- Задержка p95 или p99, не среднее: среднее не двигается, когда ломается один эндпоинт из двадцати.
- Насыщение (CPU, память, коннекты к БД, глубина очереди) — «доживёт ли до вечера»: растущая память при ровных ошибках убьёт сервис через час, а не сейчас.
- Поток запросов — объясняет остальные три: ошибки упали до нуля не потому, что починилось, а потому что балансировщик перестал слать трафик.
- Новые строки в логах: сообщение, которого не было вчера, появляется раньше, чем деградация станет видна в долях.
5.2 Технические метрики против бизнесовых
Технические реагируют за секунды и врут в сторону «всё нормально»; бизнесовые — за минуты и часы, но показывают то, что стоит денег. Классика: 5xx на нуле, задержка в норме, CPU ровный, а кнопка оплаты не отрисовалась из-за ошибки в JS, и заказы перестали создаваться. HTTP-метрики этого не увидят никогда, увидит счётчик «заказов в минуту».
Поэтому на каждую выкатку заранее назови один бизнесовый счётчик, который обязан продолжать расти, и сравнивай его с тем же часом прошлой недели: минус 40% оформлений в 3 часа ночи — норма, в 14:00 вторника — инцидент.
5.3 Сколько ждать и что считать шумом
Правило для малых чисел: если за окно прошло N запросов и ошибок не было ни одной, это значит лишь, что доля ошибок с высокой вероятностью ниже 3/N. Триста запросов без ошибок дают «меньше 1%» — при базовой норме 0.1% это не подтверждает ничего. Одна ошибка на 30 запросов — 3.3% на дашборде и ноль информации: не откатывайся, но прочитай трейс. Чтобы уверенно поймать рост доли ошибок с 0.1% до 0.5%, нужны тысячи запросов, то есть при 50 запросах в минуту — час, а не пять минут.
Горизонты: 0–5 минут — старт, рестарты, новые сообщения в логах: ловятся отсутствующие переменные окружения, несовместимость схемы, сломанная сборка. 5–30 минут — доли ошибок и задержка на реальном трафике, очереди, лаг реплики: регрессии производительности. 30 минут – 2 часа — память, коннекты, кэши: утечки и исчерпание пулов. Первые сутки — бизнес-метрики, ночные задания, обращения в поддержку: всё, что не ломается, а тихо считает неправильно. Пока не закрылось второе окно, релиз не «выкачен», а «наблюдается».
5.4 Пороги
| Сигнал | Норма | Наблюдать | Откат |
|---|---|---|---|
| Доля 5xx | базовая линия | ×2 и статистически значимо | ×5, либо любые 5xx на платежах и авторизации |
| p95 | ±10% | +30% | +100% или упирается в клиентский таймаут |
| Рестарты | 0 | 1 разовый | цикл рестартов |
| Память | плато | растёт линейно | приближается к лимиту и растёт |
| Глубина очереди | разбирается | растёт медленнее, чем разбирается | растёт монотонно 10 минут |
| Бизнес-счётчик | ±15% к тому же часу прошлой недели | −25% | −50% |
«Любые 5xx на платежах» — не преувеличение: на платёжном пути один процент это не процент, а конкретные люди с деньгами.
5.5 Медленное отравление
Отдельный класс поломок не виден ни в одном пороге: релиз работает, но пишет неправильные данные — неверный часовой пояс, потерянный знак в расчёте, перепутанные единицы, отвалившийся коннектор, из-за которого выгрузка в 1С молча уходит пустой. Ловится ровно одним способом: посмотреть на несколько свежих записей глазами и сравнить со вчерашними. Три заказа, три платежа, три строки выгрузки — три минуты работы, и ловит то, чего не поймает ни один дашборд.
6. Откат
6.1 Критерии немедленного отката
Сервис не поднимается или циклически рестартует. Любые ошибки на пути авторизации, оплаты, оформления заказа. Доля 5xx выше базовой в пять раз дольше двух минут. Данные пишутся неправильно — это хуже недоступности, потому что недоступность прекращается с откатом, а испорченные данные остаются. И самый игнорируемый критерий: ты не понимаешь, что происходит.
6.2 Почему отладка в проде дороже отката
Перед откатом потрать 60 секунд на улики — снимок логов, значения метрик, пример упавшего запроса: после отката они уйдут из горячего хранилища или перемешаются со старой версией.
6.3 Откат по слоям
Лестница с разной ценой: иди сверху вниз и остановись на первом шаге, который решает проблему.
6.4 Что делает откат невозможным
- Необратимая миграция: удалённая колонка или таблица, схлопнутые дубликаты, потеря точности при смене типа.
- Отправленные наружу сообщения: письма, пуши, Telegram, СМС. Ошибка в шаблоне рассылки не откатывается — она компенсируется вторым письмом, и это письмо тоже надо написать.
- Проведённые платежи и фискальные документы: чек не удаляется, он аннулируется отдельным документом — отдельный процесс со своими сроками.
- Данные, ушедшие во внешние системы: документы в 1С, отгрузки в МойСклад, изменённые через API цены и остатки на Ozon и Wildberries. Маркетплейс принял ваши цены — откат кода их не вернёт, нужна обратная выгрузка, и её готовят заранее.
- Записи в неизменяемых журналах и всё, что уже прочитали внешние потребители по вебхукам.
Односторонний релиз катится отдельно, маленьким, с флагом или ограничением масштаба — сначала одна организация, потом десять, потом все. Не смешивай его с двадцатью обычными изменениями: лишите отката все двадцать.
6.5 Компенсация вместо отката
Когда откат невозможен, план восстановления — это компенсация, описанная до выкатки, и она отвечает на три вопроса: как найти пострадавшие записи (конкретный запрос, а не «поищем»), как их исправить и что сказать затронутым людям.
Пример: релиз ошибочно начислил бонус существующим аккаунтам вместо новых. Откат кода начисление не отменяет — отменяет компенсирующая проводка: миграция, которая списывает начисленное с ограничением по фактическому остатку и намеренно не сбрасывает флаг «награда выдана», иначе следующая выкатка начислит бонус второй раз.
7. Окно выкатки и российская сезонность
Не катить в пятницу после обеда, в предпраздничный день и в последний час рабочего дня: проблема, всплывшая через шесть часов, обнаружится, когда автора уже нет. Катить в начале дня, лучше вторник или среда. Ночная выкатка оправдана только там, где нужен простой, и её цена — сонный человек и никого рядом. Не катить поверх незакрытого инцидента и не катить два релиза сразу: при поломке вы не будете знать, чей это релиз.
Календарь запретов; даты сверяй с календарём года, сроки отчётности — с бухгалтерией клиента (актуально на 2026-07-28).
- Конец месяца и первые дни следующего — закрытие периода, сверки, акты, зарплата: сбой выгрузки документов в 1С 30-го числа стоит дороже, чем 12-го.
- Налоговые даты. В режиме единого налогового счёта ключевые числа месяца — 25-е (уведомления и большинство деклараций) и 28-е (уплата); сервисы учётного контура в эти дни не трогают.
- Конец квартала — март, июнь, сентябрь, декабрь: сверху квартальная отчётность.
- Распродажи маркетплейсов: 11.11, конец ноября, первая половина декабря, пики перед 23 февраля и 8 марта, школьный август. Неверная цена, уехавшая на Ozon или WB в пик, — убыток за минуты, и откат вашего кода его не вернёт.
- Январские и майские каникулы — по нагрузке отличное окно, по доступности людей худшее: катите, но с явным дежурством. Понедельник утром — пик у B2B, вечер пятницы — у B2C.
Пользователь настаивает на стоп-дне — не спорь, предложи компромисс: только за флагом, выключенным по умолчанию, с включением после окна.
8. Артефакты
8.1 Запись о выкатке
Заводится до выкатки, дополняется по ходу, сохраняется документом (documents): понадобится при разборе через месяц.
Строка «Отклонения» обязательна и при успехе: выкатка, прошедшая с отклонением, — это будущий инцидент, о котором уже есть информация.
8.2 Разбор инцидента без поиска виноватого
Пишется по каждому откату и по каждой выкатке, потребовавшей внепланового вмешательства. Разбирается система, а не человек: фамилия в роли причины означает, что разбор написан неправильно, потому что «человек ошибся» не порождает исправления. Правильная формулировка — «изменение переменной окружения не проверялось ничем, кроме внимательности».
Время до обнаружения и время до восстановления лечатся разным: первое — наблюдением и алертами, второе — отработанным откатом. Команда, считающая только общее время, чинит не то.
9. Правила работы
Инструменты по шагам: git_ops — диапазон коммитов, sandbox_bash — команды выкатки, логи и миграции, repl_execute — базовая линия и значимость роста ошибок, web_fetch — health-эндпоинт, browser_interact — смоук по сценариям (о сломанном фронтенде технические метрики молчат), documents — запись и разбор, propose_schedule — проверки на +2 и +24 часа, manage_memory — базовые линии и постоянные ограничения («по 25-м и 28-м числам выкаток по учётному контуру нет»), message_compose — уведомления. Названия метрик и дашбордов клиента не выдумывай: спроси, где они лежат, или работай по логам.
Похожие навыки
Попробуйте этот навык
Зарегистрируйтесь и используйте навык «Деплой и мониторинг» бесплатно.