Skip to content

Постепенный раскат и расписание

Два способа автоматически определять значение флага — по проценту пользователей или по дате — вместо ручного переопределения.

Постепенный раскат по процентам

Вместо обычного boolean или строки флаг в опции flags может быть объектом { value, rollout }:

ts
app.use(FeatureToggles, {
  flags: {
    newSearch: { value: true, rollout: 0.2 }, // 20% пользователей
  },
  userId: currentUser.id, // стабильный идентификатор пользователя
})

rollout — число от 0 до 1. Каждый пользователь распределяется детерминированно: имя флага и userId (по умолчанию 'anonymous', если userId не задан) хешируются вместе, и пользователь получает value, если хеш попадает ниже порога rollout — иначе флаг разрешается в false, никогда в defaultValue. Один и тот же userId всегда попадает в один и тот же бакет, поэтому раскат никогда не «мигает» для конкретного пользователя между перезагрузками, а увеличение процента позже только добавляет пользователей в включённую группу, никогда не убирает.

ts
const { getRollout } = useFeatureProvider()

getRollout('newSearch') // → 0.2

Разрешение раската происходит один раз, при создании провайдера — изменение userId позже не переразбивает уже существующие флаги реактивно.

Расписание

Флаг можно принудительно выключить вне настроенного диапазона дат, независимо от ручного переопределения:

ts
app.use(FeatureToggles, {
  flags: { holidayBanner: true },
  schedule: {
    holidayBanner: { from: '2025-12-01', to: '2025-12-31' },
  },
})
ts
interface FlagSchedule {
  from?: string // ISO-дата — флаг принудительно выключен до этой даты
  to?: string // ISO-дата — флаг принудительно выключен после этой даты
}

И from, и to опциональны — опустите from для окна «активен до», или to для окна «активен с». Проверка повторяется каждую минуту, пока страница открыта, так что запланированный флаг живо переключается вкл/выкл без перезагрузки.

Расписание принудительно делает флаг false только тогда, когда он иначе разрешился бы во что-то другое — оно никогда не переопределяет активное URL-переопределение или runtime-вызов setFlag(), поэтому ручное переопределение всегда побеждает неактивное окно расписания. Полный порядок приоритета показывает, где именно расписание находится в цепочке.

ts
const { getSchedule, isScheduleActive } = useFeatureProvider()

getSchedule('holidayBanner') // → { from: '2025-12-01', to: '2025-12-31' }
isScheduleActive('holidayBanner') // → true только внутри окна (или если расписание не задано)

getFlagSource('holidayBanner') возвращает 'schedule', пока причина, по которой флаг читается как false, — неактивное окно.