Kill Switch: отключение сломанной функции без отката
Вы только что открыли новую функцию для десяти процентов пользователей. Через пять минут начинают поступать сообщения об ошибках. Функция ломает загрузку страниц для одних пользователей и повреждает данные для других. Каждую секунду, пока функция включена, страдает всё больше пользователей. Инстинкт подсказывает откатить весь деплой, но это требует времени: нужно запустить пайплайн, собрать образы, перезапустить серверы. А пользователи всё ещё натыкаются на сломанный код.
Здесь на помощь приходит kill switch — ваш аварийный тормоз.
Что на самом деле делает kill switch
Kill switch — это механизм, позволяющий отключить проблемную функцию без отката всего приложения к предыдущей версии. Если вы используете feature flags, kill switch — это просто изменение значения флага с true на false. В момент переключения флага приложение начинает выполнять старый код. Пользователи, которые видели новую функцию, возвращаются к старому интерфейсу или процессу. Никакого передеплоя. Никакого отката. Никакого ожидания завершения пайплайна.
Разница между kill switch и rollback фундаментальна. Rollback откатывает всё приложение к более ранней версии. Это означает, что отменяются все изменения из последнего релиза, включая исправления ошибок и небольшие улучшения, которые работали нормально. Rollback также требует времени: пайплайн должен выполниться, образы контейнеров — пересобраться и загрузиться, серверы — перезапуститься. Kill switch, напротив, отключает только одну функцию. Всё остальное в приложении продолжает работать на последней версии.
На временной шкале ниже показано, насколько быстрее kill switch останавливает влияние на пользователей по сравнению с полным откатом.
Вот минимальный пример того, как флаг kill switch оборачивает функцию в JavaScript:
const featureFlags = {
isEnabled(flagName) {
// В продакшене читает из удаленного конфигурационного сервиса
return config[flagName] === true;
}
};
function handleCheckout(userCart) {
if (featureFlags.isEnabled('new-checkout')) {
// Новый процесс оформления заказа с потенциальными багами
return newCheckoutFlow(userCart);
} else {
// Старый, стабильный процесс оформления заказа
return oldCheckoutFlow(userCart);
}
}
Когда флаг переключается в false, приложение мгновенно возвращается к старому коду без какого-либо передеплоя.
Когда kill switch наиболее эффективен
Kill switch особенно полезен для функций, которые только что выпущены и ещё не доказали свою стабильность. Представьте новый процесс оформления заказа, в котором оказалась ошибка в расчёте стоимости доставки. С kill switch вы можете немедленно отключить эту новую функцию. Пользователи вернутся к старой странице оформления заказа. Ваша команда может исправить ошибку без спешки, так как пользователи больше не страдают от проблемы.
Этот паттерн хорошо работает для:
- Новых UI-компонентов, которые могут сломаться под реальной пользовательской нагрузкой
- Экспериментальных функций, изменяющих основную бизнес-логику
- Интеграций со сторонними сервисами, которые ведут себя в продакшене иначе, чем в стейджинге
- Высокорисковых изменений, которые вы хотите сначала проверить на небольшой аудитории
Ключевой момент: kill switch должен чисто изолировать проблемный код. Когда флаг выключен, приложение должно вести себя точно так же, как до внедрения новой функции.
Где kill switch не работает
Kill switch — не универсальное решение. Если проблема не в самой новой функции, а в изменениях инфраструктуры или миграциях базы данных, переключение флага не поможет. Например, если новый запрос к базе данных перегружает вашу продакшен-базу, отключение feature flag может быть недостаточным, потому что запрос уже выполнился. Ущерб нанесён. В таких случаях нужен rollback или прямое исправление инфраструктуры.
Kill switch также требует тщательного проектирования в коде. Флаг, который служит kill switch, должен чисто отделять новый код от старого. Если новая функция уже изменила данные в базе, отключение флага не восстановит эти данные автоматически. Вашей команде нужно продумать эти побочные эффекты, прежде чем полагаться на kill switch.
Рассмотрим функцию, которая пишет в новую таблицу базы данных. Когда вы переключаете kill switch, приложение перестаёт писать в эту таблицу, но данные, которые уже были записаны, остаются. Если старый код не читает из этой таблицы, устаревшие данные могут не вызвать немедленных проблем. Но если старый код ожидает данные в другом формате или расположении, могут возникнуть несоответствия, которые будет сложно распутать позже.
Комбинация kill switch с circuit breaker
Некоторые команды сочетают kill switch с circuit breaker. Circuit breaker автоматически отключает функцию, когда уровень ошибок превышает заданный порог. Например, если уровень ошибок превышает пять процентов в течение одной минуты, circuit breaker отключает функцию без участия человека.
Такая комбинация особенно полезна для функций, которые работают в нерабочее время или когда ваша команда не на дежурстве. Circuit breaker выступает в роли автоматической страховочной сети, а kill switch даёт вам ручное управление, когда нужно действовать быстрее, чем автоматическая система.
Паттерн circuit breaker добавляет ещё один слой: он может обнаружить, когда основная проблема устранена, и постепенно вернуть трафик на функцию. Это делает его более сложным, чем простой kill switch, но и более сложным в реализации и тестировании.
Что происходит после активации kill switch
Переключение kill switch — это экстренная реакция, а не постоянное решение. После отключения функции вашей команде нужно найти первопричину. Функция, которая была отключена, не заброшена. Вы исправляете баг, тестируете исправление и снова включаете флаг.
Если не довести дело до конца, флаг останется в кодовой базе навсегда. Мёртвые флаги становятся техническим долгом. Они засоряют код, сбивают с толку будущих разработчиков и увеличивают риск случайного включения сломанной функции спустя месяцы.
Практический чек-лист для kill switch
Прежде чем полагаться на kill switch в продакшене, проверьте:
- Может ли флаг чисто отделить новый код от старого без побочных эффектов?
- Оставляет ли отключение функции данные в согласованном состоянии?
- Доступен ли переключатель флага дежурной команде без необходимости деплоя?
- Тестировали ли вы поведение kill switch в стейджинге?
- Знает ли команда, кто имеет право переключать kill switch?
- Есть ли документированный процесс действий после активации kill switch?
Конкретный вывод
Kill switch даёт вам возможность отключить одну функцию за секунды без отката всего приложения. Это не замена rollback или надлежащему тестированию, но это критически важный механизм безопасности для любой команды, которая выпускает функции инкрементально. Проектируйте свои feature flags так, чтобы они могли служить kill switch. Тестируйте, что они действительно работают. И когда вы переключаете один из них, воспринимайте это как начало цикла исправления, а не конец обсуждения.