Feature flags (Kill Switch)
Коротко: Переключатель, который можно менять во время работы и с помощью которого отдельные некритичные функции включаются/выключаются без развёртывания — например, чтобы оперативно отключить их при высокой нагрузке на сервер.
Подробнее: Важно намеренное разделение между функциями «приятно иметь», которые можно переключать таким переключателем, и критичными основными функциями (оформление заказа, вход), которые им никогда не должны отключаться, — иначе переключатель «снизить нагрузку» случайно становится переключателем «отключить выручку». Если сама система хранения (здесь Redis) выходит из строя, запасное поведение должно быть всегда «всё включено», никогда не «всё выключено».
Наш контекст: В Emzett app/utils/featureFlags.ts намеренно использует Upstash Redis вместо таблицы site_settings в Postgres — весь смысл kill switch в том, чтобы НЕ создавать дополнительных чтений Postgres, когда система под нагрузкой. Сейчас используется только для звуковых эффектов и всплывающего окна отзывов, с 30-секундным кэшем в памяти на экземпляр Lambda.
Подробности
На практике feature flags используются для очень разных целей, существенно различающихся по требованиям: kill switch (это понятие — быстро выключить что-то в чрезвычайной ситуации, обычно двоичное вкл/выкл, затрагивает всех пользователей одинаково), постепенные выкатки (сначала включить новую функцию для 5 % пользователей, затем медленно наращивать, чтобы ограничить риск неисправного релиза) и A/B-тесты (параллельно показывать два варианта разным группам пользователей, чтобы измерить, какой работает лучше). У kill switch самые жёсткие требования ко времени реакции — в чрезвычайной ситуации (например, неисправная, создающая нагрузку функция) важна каждая секунда, пока переключатель ещё не подействовал.
Кэш в памяти на экземпляр — намеренный компромисс между согласованностью и скоростью: если вы меняете флаг, проходит до 30 секунд, пока все экземпляры сервера подхватят новое значение (вместо немедленного), но взамен не каждый запрос вызывает новый обмен с Redis. Для kill switch, который при сомнении должен подействовать «в течение минуты», а не «немедленно», это приемлемый компромисс — для включения платежей такая задержка может быть неприемлема.
Fail-open и fail-closed
Центральное проектное решение в любой системе feature flags — как она ведёт себя, когда сам источник флагов (здесь Redis) недоступен: fail-open означает, что при сомнении функция считается ВКЛЮЧЁННОЙ (нормальное состояние до введения флага) — разумно для некритичных функций, где кратковременно активная функция безвреднее ошибочно отключённой. Fail-closed — наоборот, при сомнении ВЫКЛЮЧЕНО — разумно для флагов, связанных с безопасностью (например, флага, управляющего ещё не готовой, потенциально неисправной платёжной функцией). Система kill switch практически всегда должна быть fail-open, поскольку её цель — именно отключать существующие работающие функции; если рухнет сама инфраструктура флагов, это не должно автоматически отключить и ВСЕ функции.
Отличие от переменных окружения
Более простая альтернатива настоящей системе feature flags — обычные переменные окружения, но их изменение всегда требует нового развёртывания, потому что они читаются только при запуске процесса. Kill switch через Redis/базу данных можно менять во время работы, без развёртывания и без перезапуска работающих экземпляров сервера — именно та экономия времени, которая важна в чрезвычайной ситуации.
См. также: Upstash Redis, Ограничение частоты запросов, Служба