Bandera (bandera v0.1.0)

Copy Markdown

Runtime-configured feature flags, API-compatible with fun_with_flags.

The active store is resolved at runtime (Bandera.Store.active/0), so nothing about persistence or caching is fixed at compile time.

Summary

Functions

Returns {:ok, names} with every known flag name, or {:error, reason}.

Returns {:ok, flags} with every stored Bandera.Flag, or {:error, reason}.

Removes gates from flag_name, returning :ok.

Disables flag_name, optionally scoped by an option, and returns {:ok, enabled?}.

Enables flag_name, optionally scoped by an option, and returns {:ok, enabled?}.

Returns whether flag_name is enabled.

Looks up a single flag, returning {:ok, %Bandera.Flag{}} or {:error, reason}.

Re-read application env into the runtime config snapshot.

Functions

all_flag_names()

@spec all_flag_names() :: {:ok, [atom()]} | {:error, term()}

Returns {:ok, names} with every known flag name, or {:error, reason}.

Examples

iex> Bandera.enable(:checkout)
iex> Bandera.all_flag_names()
{:ok, [:checkout]}

all_flags()

@spec all_flags() :: {:ok, [Bandera.Flag.t()]} | {:error, term()}

Returns {:ok, flags} with every stored Bandera.Flag, or {:error, reason}.

Examples

iex> Bandera.enable(:checkout)
iex> {:ok, flags} = Bandera.all_flags()
iex> Enum.map(flags, & &1.name)
[:checkout]

clear(flag_name, options \\ [])

@spec clear(
  atom(),
  keyword()
) :: :ok | {:error, term()}

Removes gates from flag_name, returning :ok.

With no options the whole flag (all its gates) is deleted. A scope removes just that gate, letting evaluation fall through to whatever remains:

  • boolean: true — clear the boolean gate
  • for_actor: actor — clear one actor gate
  • for_group: group — clear one group gate
  • for_percentage: true — clear the percentage gate

Returns {:error, reason} if the store delete fails.

Examples

iex> Bandera.enable(:checkout)
iex> Bandera.clear(:checkout)
:ok
iex> Bandera.enabled?(:checkout)
false

disable(flag_name, options \\ [])

@spec disable(
  atom(),
  keyword()
) :: {:ok, boolean()} | {:error, term()}

Disables flag_name, optionally scoped by an option, and returns {:ok, enabled?}.

Accepts the same scopes as enable/2 (for_actor:, for_group:, for_percentage_of:). For a percentage scope, disabling for ratio is equivalent to enabling for 1.0 - ratio. Returns {:error, reason} on a store write failure.

Examples

iex> Bandera.disable(:checkout)
{:ok, false}

iex> Bandera.enable(:beta)
iex> Bandera.disable(:beta)
{:ok, false}

enable(flag_name, options \\ [])

@spec enable(
  atom(),
  keyword()
) :: {:ok, boolean()} | {:error, term()}

Enables flag_name, optionally scoped by an option, and returns {:ok, enabled?}.

With no options the boolean gate is turned on. Supported scopes:

  • for_actor: actor — enable for one actor
  • for_group: group — enable for a named group
  • for_percentage_of: {:time, ratio} — enable for a ratio of calls
  • for_percentage_of: {:actors, ratio} — enable for a ratio of actors

ratio is a float in 0.0 < r < 1.0. The write goes to the persistent store and busts/refreshes the cache; returns {:error, reason} if the store write fails.

Examples

iex> Bandera.enable(:checkout)
{:ok, true}

iex> Bandera.enable(:beta, for_actor: "user-1")
{:ok, true}

iex> Bandera.enable(:gradual, for_percentage_of: {:actors, 0.25})
{:ok, true}

enabled?(flag_name, options \\ [])

@spec enabled?(
  atom(),
  keyword()
) :: boolean()

Returns whether flag_name is enabled.

Pass for: actor to evaluate actor, group, and percentage-of-actors gates against a specific subject (the actor is identified via the Bandera.Actor/Bandera.Group protocols). The flag is read through the active store (cache included). A missing flag, or a store lookup error, resolves to false (the error is logged).

Examples

iex> Bandera.enabled?(:unknown_flag)
false

iex> Bandera.enable(:checkout)
iex> Bandera.enabled?(:checkout)
true

iex> Bandera.enable(:beta, for_actor: "user-1")
iex> Bandera.enabled?(:beta, for: "user-1")
true
iex> Bandera.enabled?(:beta, for: "user-2")
false

get_flag(flag_name)

@spec get_flag(atom()) :: {:ok, Bandera.Flag.t()} | {:error, term()}

Looks up a single flag, returning {:ok, %Bandera.Flag{}} or {:error, reason}.

An unknown flag still returns {:ok, flag} with an empty gate list (a disabled flag), not an error.

Examples

iex> Bandera.enable(:checkout)
iex> {:ok, flag} = Bandera.get_flag(:checkout)
iex> flag.gates
[%Bandera.Gate{type: :boolean, for: nil, enabled: true}]

iex> {:ok, flag} = Bandera.get_flag(:unknown_flag)
iex> flag.gates
[]

reload_config()

@spec reload_config() :: :ok

Re-read application env into the runtime config snapshot.