Когда откат слишком рискован: как roll-forward помогает системе двигаться дальше
Вы выкатываете новую версию приложения в пятницу после обеда. Дашборды мониторинга показывают, что всё в порядке. Вы уходите домой. В субботу утром заглядываете в телефон и видите баг-репорт: пользователи, зарегистрировавшиеся после деплоя, не могут завершить настройку профиля. В базе появилась новая таблица, где хранятся их неполные данные. Теперь нужно принять решение.
Откатиться на предыдущую версию? А что тогда делать с данными в новой таблице? Те, кто уже заполнил профили, потеряют прогресс. Схема БД изменилась, и обратное изменение означает удаление таблицы, в которой уже есть реальные пользовательские данные. То, что в пятницу казалось простым откатом, теперь выглядит как инцидент с потерей данных.
В этот момент многие команды понимают: откат — не всегда самый безопасный вариант. Есть другой путь: roll-forward.
Что такое roll-forward на самом деле
Roll-forward — это противоположность откату. Вместо возврата к старой версии вы создаёте новую, которая исправляет проблему, и выкатываете её в продакшен. Вы продолжаете движение вперёд, добавляя исправление, а не отменяя изменения.
Логика проста: если в текущей версии есть баг, напишите патч, который его чинит, и отправьте его. База данных остаётся как есть. Новая таблица остаётся. Данные пользователей остаются. Вы просто чините код, который сломал процесс настройки профиля.
Поначалу такой подход кажется нелогичным. Большинство инженеров с детства усвоили: если что-то сломалось — отмени. Но в современных системах, особенно с изменениями в БД, отмена часто оказывается сложнее, чем исправление на ходу.
Когда roll-forward имеет больше смысла, чем откат
Roll-forward особенно полезен в трёх типичных ситуациях.
Изменения БД, которые уже попали в продакшен
Это самая частая причина, по которой команды выбирают roll-forward. Если деплой включает миграцию БД, откат кода приложения — только половина дела. Нужно ещё откатить изменения в базе. Если миграция добавила колонку — её нужно удалить. Если создала новую таблицу — её нужно дропнуть. А если в этой таблице уже есть данные реальных пользователей, дроп означает потерю этих данных.
Некоторые команды пишут обратимые миграции специально для откатов. Но даже с ними остаётся проблема данных. Пользователи ввели информацию. Транзакции записаны. Связи между таблицами установлены. Откат схемы не отменяет данные, которые были введены в рамках новой схемы.
В этой ситуации roll-forward означает: оставляем БД как есть, чиним код приложения и деплоим снова. Пользователи сохраняют данные. Схема остаётся консистентной. Меняется только бажный код.
Проблемы, обнаруженные через часы или дни
Не все баги находятся сразу. Некоторые проявляются после того, как пользователи некоторое время поработали с системой. К моменту, когда вы замечаете проблему, новая версия уже обработала тысячи транзакций, создала сотни записей и изменила состояние системы так, что обратить это сложно.
Откат в таком сценарии означает потерю всей этой активности. Пользователи, оформившие заказы, обновившие профили или отправившие формы, увидят, что их работа пропала. Посыплются обращения в поддержку. Доверие будет подорвано.
Roll-forward позволяет исправить баг, не трогая данные, которые пользователи уже создали. Исправление ложится поверх всего, что произошло после деплоя.
Критичные системы, где недоступность недопустима
Некоторые системы не могут позволить себе время, необходимое для отката. Откат — это не мгновенно. Нужно откатить код, откатить БД, проверить, что всё работает, и надеяться, что ничего не сломается. Для систем, обслуживающих платящих клиентов или работающих в реальном времени, такое окно неопределённости слишком велико.
Roll-forward позволяет системе оставаться в работе. Вы готовите исправление, тестируете его максимально быстро и деплоите. Система работает всё это время. Пользователи могут видеть баг чуть дольше, но они не увидят даунтайма.
Как roll-forward работает на практике
Процесс почти не отличается от обычного деплоя. Вы создаёте ветку от текущего продакшен-кода. Пишете исправление. Запускаете пайплайн. Разница — в срочности и возможных сокращениях.
Многие команды выделяют отдельный пайплайн для hotfix-ов. Он пропускает некритичные стадии вроде долгих тестов производительности или сканирования безопасности. Процесс ревью ускоряется. Тестирование фокусируется на конкретном исправлении и областях, которые оно может затронуть. Цель — доставить исправление в продакшен как можно быстрее, но при этом не пропустить очевидные проблемы.
Ключевое противоречие roll-forward — скорость против тщательности. Если баг критический, можно пропустить некоторые проверки. Если баг незначительный — можно позволить себе быть аккуратнее. Универсального правила нет. Каждая команда решает, исходя из серьёзности проблемы и риска внести новые ошибки.
Риски roll-forward
Roll-forward — не бесплатный билет. У него есть свои риски.
Самый большой риск — ваше исправление внесёт новый баг. В спешке вы можете не до конца понять первопричину. Вы залатаете симптом, но упустите корневую проблему. Исправление уходит, и теперь у вас две проблемы вместо одной.
Другой риск — исправление плохо взаимодействует с существующим кодом. Бажная версия могла изменить какое-то поведение, от которого зависит ваш патч. Вы можете случайно сломать то, что раньше работало нормально.
Некоторые команды используют гибридный подход: сначала откатываются, чтобы стабилизировать систему, а потом спокойно разбираются с первопричиной и готовят нормальное исправление. Это хорошо работает, когда откат безопасен, а система может пережить кратковременное возвращение к предыдущему состоянию. Но когда откат рискован — roll-forward становится лучшим выбором.
Как выбрать между откатом и roll-forward
Решение сводится к простому вопросу: какой вариант несёт меньший суммарный риск?
Следующая блок-схема обобщает описанную выше логику принятия решений.
Для приложений без существенных изменений в БД откат обычно быстрее и безопаснее. Вы откатываете код, система возвращается в предыдущее состояние, и у вас есть время спокойно исправить проблему.
Для деплоев, которые изменили схему БД или работали достаточно долго, чтобы накопить новые данные, roll-forward часто оказывается более разумным выбором. Стоимость отмены изменений данных выше, чем стоимость написания и выкатки исправления.
После того как исправление выкачено
Roll-forward не заканчивается, когда исправление попало в продакшен. Нужно убедиться, что оно действительно работает и ничего больше не сломалось. Следите за частотой ошибок. Проверьте затронутую функциональность. Ищите необычные паттерны в логах.
Шаг верификации легко пропустить, когда вы устали и хотите просто закрыть инцидент. Но именно так маленькие инциденты превращаются в большие. Уделите пять минут, чтобы подтвердить: исправление сделало то, что должно было.
Практический чек-лист для roll-forward
Используйте его, когда решаете двигаться вперёд вместо отката:
- Убедитесь, что откат приведёт к потере данных или нарушению консистентности схемы
- Определите точный баг и напишите минимальное исправление
- Запустите тесты, покрывающие сценарий с багом и окружающую функциональность
- Выкатите через обычный пайплайн, пропуская только некритичные стадии, если срочность требует
- Мониторьте частоту ошибок, время отклика и затронутую функциональность в течение 30 минут после деплоя
- Задокументируйте, что произошло и почему был выбран roll-forward вместо отката
Вывод
Roll-forward — это не признак неудачи. Это практичный ответ на реальность: некоторые изменения невозможно чисто отменить. Когда база данных изменилась, пользователи ввели данные, система ушла вперёд — самый безопасный способ исправить проблему часто заключается в том, чтобы продолжать движение вперёд с лучшей версией.
Вопрос не в том, понадобится ли вам когда-нибудь roll-forward. Вопрос в том, готова ли ваша команда вовремя распознать, что откат — неправильный выбор, и действовать соответственно.