Реализация OpenFeature - открытого стандарта CNCF для оценки фича-флагов - на OneScript.
Прикладной код работает с флагами через единый API и ничего не знает о том, где они хранятся. Систему управления флагами можно заменить, поменяв одну строку регистрации провайдера: локальный JSON на старте, свой сервер в проде, набор в памяти в тестах.
opm install openfeature
#Использовать openfeature
// Один раз при старте приложения
OpenFeature.УстановитьПровайдер(Новый JsonFileProvider("flags.json"));// Дальше вездеКлиент= OpenFeature.ПолучитьКлиента();Если Клиент.ПолучитьЛогическое("new-checkout",Ложь) Тогда
ПоказатьНовуюКорзину();КонецЕсли;Оценка никогда не выбрасывает исключений. Недоступный провайдер, отсутствующий флаг, неверный тип значения - во всех случаях вернётся переданное значение по умолчанию. Флаги не должны ронять приложение.
Контекст=Новый EvaluationContext("user-42",Новый Структура("plan","pro"));Тема= Клиент.ПолучитьСтроку("тема","light", Контекст);Ключ таргетинга - идентификатор субъекта оценки: по нему провайдеры закрепляют пользователя за вариантом, чтобы процентные выкатки были стабильными.
Контекст уровня приложения задаётся один раз и объединяется с контекстом вызова, причём контекст вызова имеет приоритет:
OpenFeature.УстановитьГлобальныйКонтекст(Новый EvaluationContext("",Новый Структура("окружение","prod")));Детали= Клиент.ПолучитьСтрокуСДеталями("тема","light", Контекст);Сообщить(Детали.Значение);// darkСообщить(Детали.Вариант);// тёмнаяСообщить(Детали.Причина);// TARGETING_MATCHСообщить(Детали.КодОшибки);// пусто при успехеПровайдеры InMemoryProvider и JsonFileProvider понимают два вида описания. Простое - сразу значение:
{
"new-checkout": true,
"максимум-позиций": 25
}Развёрнутое - с вариантами и правилами таргетинга:
{
"тема": {
"Варианты": { "светлая": "light", "тёмная": "dark" },
"ВариантПоУмолчанию": "светлая",
"Правила": [
{ "Атрибут": "plan", "Значения": ["pro", "enterprise"], "Вариант": "тёмная" }
]
},
"выключенный": { "Значение": true, "Включен": false }
}Правила проверяются по порядку, побеждает первое совпавшее; если ни одно не сработало, берётся вариант по умолчанию. Выключенный флаг всегда отдаёт значение по умолчанию с причиной DISABLED.
В коде набор флагов удобнее задавать Соответствием: ключи флагов обычно содержат дефис, а Структура такие имена не допускает.
Флаги=Новый Соответствие();
Флаги.Вставить("new-checkout",Истина);
OpenFeature.УстановитьПровайдер(Новый InMemoryProvider(Флаги));Хук - объект с методами До, После, ПриОшибке, Финально; реализовать можно любое подмножество.
ФункцияДо(ЗначДанные,ЗначПодсказки) Экспорт// Можно дополнить контекст - возвращённые атрибуты имеют приоритетВозвратНовый EvaluationContext("",Новый Структура("окружение","prod"));КонецФункцииПроцедураПосле(ЗначДанные,ЗначДетали,ЗначПодсказки) Экспорт
Метрики.Учесть(Данные.КлючФлага, Детали.Вариант);КонецПроцедурыOpenFeature.ДобавитьХук(Новый ХукМетрик());// для всех клиентов
Клиент.ДобавитьХук(Новый ХукАудита());// для одного клиентаСтадия До выполняется от глобальных хуков к локальным, а После, ПриОшибке и Финально - в обратном порядке. Сбой хука не роняет оценку: она завершается штатным отказом со значением по умолчанию.
| Метод | Возвращает | Описание |
|---|---|---|
УстановитьПровайдер(Провайдер) | - | Регистрирует провайдера, инициализирует его и завершает предыдущего |
ПолучитьКлиента(Домен = "") | FeatureClient | Клиент оценки |
ДобавитьХук(Хук) | - | Хук для всех клиентов |
УстановитьГлобальныйКонтекст(Контекст) | - | Контекст уровня приложения |
ГлобальныйКонтекст() | EvaluationContext | Текущий глобальный контекст |
Провайдер() / МетаданныеПровайдера() / СостояниеПровайдера() | Сведения о провайдере | |
Завершить() | - | Сброс всего состояния API |
СоздатьИзолированныйЭкземпляр() | OpenFeatureApi | Независимый экземпляр API |
ПолучитьЛогическое, ПолучитьСтроку, ПолучитьЧисло, ПолучитьОбъект и их варианты …СДеталями. Сигнатура: (Ключ, ЗначениеПоУмолчанию, Контекст = Неопределено, Параметры = Неопределено), где Параметры - структура с полями Хуки и ПодсказкиХуков.
Также ДобавитьХук(Хук), Метаданные(), СостояниеПровайдера().
КлючТаргетинга(), УстановитьКлючТаргетинга(Значение), Установить(Имя, Значение), Получить(Имя, ЗначениеПоУмолчанию), Содержит(Имя), Атрибуты(), Объединить(Другой), Количество().
Свойства КлючФлага, Значение, Вариант, Причина, КодОшибки, СообщениеОбОшибке, МетаданныеФлага; методы ЭтоОшибка(), Метаданное(Имя, ЗначениеПоУмолчанию).
Константы вместо строковых литералов: OpenFeatureReason.СовпадениеТаргетинга() → TARGETING_MATCH, OpenFeatureErrorCode.ФлагНеНайден() → FLAG_NOT_FOUND и так далее.
Провайдер - объект со следующими методами:
ФункцияМетаданные() Экспорт// Структура("Имя", "МойПровайдер")ПроцедураИнициализировать(ЗначКонтекст) ЭкспортПроцедураЗавершить() ЭкспортФункцияСостояние() Экспорт// NOT_READY, READY, ERROR, STALE, FATALФункцияВычислитьЛогическое(ЗначКлюч,ЗначЗначениеПоУмолчанию,ЗначКонтекст) ЭкспортФункцияВычислитьСтроку(ЗначКлюч,ЗначЗначениеПоУмолчанию,ЗначКонтекст) ЭкспортФункцияВычислитьЧисло(ЗначКлюч,ЗначЗначениеПоУмолчанию,ЗначКонтекст) ЭкспортФункцияВычислитьОбъект(ЗначКлюч,ЗначЗначениеПоУмолчанию,ЗначКонтекст) ЭкспортКаждый метод оценки возвращает ResolutionDetails:
ФункцияВычислитьЛогическое(ЗначКлюч,ЗначЗначениеПоУмолчанию,ЗначКонтекст) ЭкспортЕсли НеНашли(Ключ) ТогдаРезультат=Новый ResolutionDetails(ЗначениеПоУмолчанию);Возврат Результат.ЗаполнитьОшибку(OpenFeatureErrorCode.ФлагНеНайден(),"Флаг не найден", ЗначениеПоУмолчанию);КонецЕсли;ВозвратНовый ResolutionDetails(Значение, OpenFeatureReason.СовпадениеТаргетинга(),"вариант-а");КонецФункцииРеализованы обязательные требования разделов Flag Evaluation, Providers, Evaluation Context и Hooks:
- API - глобальный синглтон; есть и фабрика изолированных экземпляров (раздел 1.8).
- Регистрация провайдера вызывает
Инициализироватьу нового иЗавершитьу предыдущего. - До регистрации провайдера работает заглушка, возвращающая значения по умолчанию с причиной
DEFAULT. - Клиент не выбрасывает исключений и гарантирует тип: значение неожиданного типа заменяется значением по умолчанию с кодом
TYPE_MISMATCH. EvaluationDetailsсодержит ключ флага, значение, вариант, причину, код и сообщение об ошибке; поле метаданных при отсутствии данных - пустая запись, а неНеопределено.- Причины и коды ошибок соответствуют перечням спецификации.
- Порядок стадий хуков и слияние контекстов - по спецификации; ошибка в хуке приводит к штатному отказу оценки.
Не реализовано в этой версии: события провайдера (PROVIDER_READY, PROVIDER_CONFIGURATION_CHANGED и прочие), транзакционный контекст, доменные провайдеры (ПолучитьКлиента("домен") возвращает клиент с метаданными домена, но привязка отдельного провайдера к домену не поддерживается), tracking API.
opm install -l
oneunit execute -d ./tests