Как мы управляем тысячами тогглов в сотнях сервисов
Когда в компании сотни сервисов, рано или поздно возникает вопрос: как управлять фича-тогглами единообразно, чтобы не создавать множество админок?
Мы разработали Thermostat — централизованный сервис для удаленного управления функционалом приложений в реальном времени. В статье рассказываем, что у него внутри: OpenFeature SDK, версионирование конфигураций, поддержка динамических правил и плавной выкатки.
Thermostat реализует парадигму Feature Toggles и Remote Config. Вместо того, чтобы жестко зашивать значения в код или дергать разрозненные админки, разработчики оборачивают функционал в параметры, значения которых управляются через единую административную панель. Это дает несколько ключевых возможностей: гибко включать и выключать функционал без перезапуска приложения, постепенно раскатывать новые фичи на целевую аудиторию, экстренно откатывать проблемные изменения и таргетировать доставку согласно бизнес-сценариям.
Доменная модель Thermostat строится вокруг трех основных сущностей:
- Application — это приложение или сервис, который создает логическую группировку для параметров.
- Parameter — тоггл или конфигурационная переменная с определенным типом данных (int, bool, string, json).
- Environment — виртуальное окружение (dev, stage, prod и т. д.) с привязкой к определенному контуру test, prod, или public, что определяет сетевой сегмент доступа и ролевую модель для управления конфигурацией в админке.
В приложении происходит управление параметрами, которые едины для всех окружений — добавляя или удаляя параметр, мы производим это действие для всех окружений сразу.
Пользователи получают единый UX независимо от того, с каким контуром работают — test, prod или public. Параметр и его возможные значения создаются один раз и становятся доступны на всех окружениях. Для boolean параметров опции не требуются, для остальных нужно явно определить допустимые значения, которые уже можно выбрать при конфигурации определенного окружения (create once, use anywhere). Предусмотрена возможность задавать in-code default — значение по умолчанию из кода, которое всегда доступно для выбора и позволяет передать контроль над параметром в конкретную сборку приложения.
Для сложных конфигураций Thermostat поддерживает JSON-параметры с обязательной JSON Schema. При создании нового значения система проверяет их соответствие схеме, а при изменении схемы — что все существующие опции (значения) удовлетворяют новой схеме. Таким образом достигается реализация обратной совместимости для схемы.
Состояние параметров на каждом окружении хранится в специальной сущности — config set. При каждом изменении версия config set инкрементируется. Также у каждого параметра внутри config set есть своя версия, что позволяет отслеживать историю изменений как всей конфигурации, так и каждого параметра в нем на всех окружениях.
В основе клиентской части — спецификация OpenFeature, которая дает единый интерфейс для работы с параметрами независимо от стека. SDK работает с конфигурацией in-memory и периодически обновляет ее в фоне, получая только изменившиеся параметры (инкрементальное обновление), а для динамических параметров делает индивидуальные запросы и кеширует. В ответе передаются метаданные из админки (поскольку все версионируется), которые можно пробросить в логи и метрики для получения observability, чтобы было понимание, что и в какой момент доехало до приложения в runtime.
Для сценариев, где значение параметра зависит от контекста вызова (например, от пользователя или версии приложения), Thermostat поддерживает динамические правила. Каждое состоит из выражений, объединенных по И/ИЛИ. В выражениях используются атрибуты контекста из заранее определенного списка. Это сознательное ограничение, чтобы не заводить бизнес-логику в сервисе фича-тогглов. На один параметр можно назначить до трех правил с соответствующими им опциями.
Для реализации А/Б-тестирования и персонализации Thermostat будет интегрирован с бизнес-платформой Hippo. Такое разделение позволяет использовать разные доменные модели и пользовательские сценарии (UX) для задач, связанных с разработкой и бизнес-персонализацией, а также развивать системы независимо, с фокусом на потребности своей аудитории. При этом Thermostat выступает в роли «мостика» к Hippo и, по сути, является технической платформой.
Сервис построен на Java и архитектурно разделен на два основных компонента: административную панель (control-desk) и сервис раздачи конфигураций (provider). Данные хранятся в PostgreSQL и S3, для управления очередями используется Kafka, для аналитики — Clickhouse. Интерфейс административной панели разработан на React и встроен в IDP Spirit. API описано в спецификации OpenAPI с применением подхода API-first. Поддерживаются SDK для большинства основных языков и фреймворков: Java, Kotlin, Scala, Go, Python, C++, TypeScript, JavaScript, Node.js, .NET, Nest.js, React, Angular. Недавно добавилась поддержка Rust — благодаря иннерсорсу и OpenFeature.