View Source Unleash (Unleash v2.0.0-git-4b61)

Unofficial Elixir SDK for the Unleash Feature Flag System.

Like all the official SDKs, this one keeps and serves feature from a local cache (in our case, based on an :ets table), including evaluating activation strategies locally. The features are initialised from a bootstrap file and updated periodically from the Unleash API in the background, independently of how many feature checks are invoked.

This allows applications using this SDK to get the status of a feature instanteneously and locally, without overloading the Unleash Server with API calls; but it also means that the features might be stale, upto the polling interval or even longer in case of errors contacting the Unleash APIs.

The SDK is an Elixir Application that comes with its own Supervision Tree, which starts two GenServer worker processes:

  • Unleash.Repo, responsible for periodically refreshing the features from the Unleash API Server and maintaining the local cache updated.
  • Unleash.Metrics, responsible for periodically sending metrics to the Unleash API Server.

The latter can be disabled with disable_metrics: true; while setting disable_client: true will disable both of them and the SDK will start in "disconnected mode", where no features are defined and feaure flags values are returned only from local overrides (see Unleash.Propagation) and fallback values.

Note that:

  • In "disconnected mode", at the moment the SDK won't even load features from the local bootstrap file. That might change in the future, which would allow the SDK to work with a static set of local features initialised from a local file.
  • In the test environment, the SDK won't automatically start polling from the API, even if the client is enabled. You'll have to start it explicitely with Unleash.Repo.start_polling/0.

Summary

Types

The Unleash Context, mostly used to evaluate conditional activation strategies. https://docs.getunleash.io/reference/unleash-context.

Option that can be passed to enabled?/2 and runtime_enabled?/2.

Type that can be used to reference a feature.

Option that can be passed to get_variant/2 and runtime_get_variant/2.

Record of a feature flag activation check.

Represents local feature overrides that can be used to force a feature evaluation value, bypassing its activation strategies.

Functions

Checks if the given feature is enabled.

Looks for a context value, taking care of some of the nasty details like fallback to :properties (a.k.a. custom context values) with support for both atom and string keys.

Returns the variant for the given feature flag.

Runtime-friendly version of enabled?/2 with support for runtime option keys.

Runtime-friendly version of get_variant/2 with support for runtime option keys.

Starts the Unleash SDK.

Types

@type context() :: %{
  optional(:app_name) => String.t(),
  optional(:environment) => String.t(),
  optional(:user_id) => String.t(),
  optional(:session_id) => String.t(),
  optional(:remote_address) => String.t(),
  optional(:properties) => %{required(atom() | String.t()) => String.t()},
  optional(:current_time) => String.t()
}

The Unleash Context, mostly used to evaluate conditional activation strategies. https://docs.getunleash.io/reference/unleash-context.

Custom context properties can be defined in the :properties field. Note that, for hystorical / backwards-compatibility reasons, both atom and string keys are allowed in the properties map. You are encouraged to use find_in_context/2 to lookup context values in a way that handles fallback to properties and the different style of keys correctly.

@type enabled_opt() ::
  {:allow_overrides, boolean()}
  | {:context, context()}
  | {:fallback, boolean() | nil}

Option that can be passed to enabled?/2 and runtime_enabled?/2.

  • :allow_overrides - Whether propagated overrides should be considered for the feature flag check. See Unleash.overrides/0. The default is false.
  • :context - Context that might be used to evaluate activation strategies. The default is an empty map.
  • :fallback - Fallback value that will be returned if the feature is not found in the local cache or overrides. The default is false. You can use nil if you'd like to handle missing features explicitly.
@type feature_name() :: String.t() | atom()

Type that can be used to reference a feature.

Note that :feature_a and "feature_a" reference the same feature.

@type get_variant_opt() ::
  {:allow_overrides, boolean()}
  | {:context, context()}
  | {:fallback, Unleash.Variant.result() | nil}

Option that can be passed to get_variant/2 and runtime_get_variant/2.

  • :allow_overrides - Whether propagated overrides should be considered for the feature flag check. See Unleash.overrides/0. The default is false.
  • :context - Context that might be used to evaluate activation strategies. The default is an empty map.
  • :fallback - Fallback value that will be returned if the feature is not found in the local cache or overrides. The default is the special "disabled" variant. You can use nil if you'd like to handle missing features explicitly.
@type impression() :: %{feature_name: String.t(), enabled: boolean()}

Record of a feature flag activation check.

In other words, whenever a feature flag is queried for status via enabled?/3, an impression represents the feature that was checked and the result of that check. See https://docs.getunleash.io/reference/impression-data

@type overrides() :: %{required(String.t()) => :on | :off | String.t()}

Represents local feature overrides that can be used to force a feature evaluation value, bypassing its activation strategies.

These can be inherited from the clients, see Unleash.Propagation for a high-level introduction to the topic.

Functions

Link to this function

atomize_context_key(string_key)

View Source
@spec atomize_context_key(String.t()) :: atom()
Link to this macro

enabled?(feature_name_ast, opts_ast \\ [])

View Source (macro)

Checks if the given feature is enabled.

Takes a feature name and a set of extra parameters (in the form of a keyword list) that customise the behaviour of the feature check, see enabled_opt/0 for the supported parameters and their defaults.

Returns a boolean indicating whether the feature flag is enabled. Can return nil only if :fallback was set to nil and the feature was not found locally.

Examples

iex> Unleash.enabled?(:flag_a)
iex> Unleash.enabled?(:flag_b, context: get_context(), fallback: true, allow_overrides: false)

Compile-time option keys only

Whenever you call Unleash.enabled/2, option keys must be provided statically at compile-time, similar to how you would use function call syntax. The compiler will raise an error when that's not the case.

This requirement does not extend to the feature name or option values, which can be dynamic runtime terms. However, for the sake of readability and clarity regarding which/how feature flags are being checked, it is recommended to also provide those statically whenever possible, particularly for feature names.

For instance, rather than writing:

iex> opts = [allow_overrides: true, fallback: true]
...> {name, opts} = case some_condition do
...>   true -> {:flag1, Keyword.put(opts, :context, %{user_id: "u-42"})}
...>   false -> {:flag2, opts}
...> end
...> Unleash.enabled?(name, opts)

You should write:

iex> case some_condition do
...>   true -> Unleash.enabled?(:flag1, allow_overrides: true, fallback: true, context: %{user_id: "u-42"})
...>   false -> Unleash.enabled?(:flag2, allow_overrides: true, fallback: true)
...> end

In the second example, it is much clearer to see which feature flags are being checked and the parameters being used.

If you absolutely need to pass the options using arbitrary runtime expressions (which is extremely unlikely), you can use runtime_enabled?/2, but its usage is discouraged.

Link to this function

find_in_context(context, key)

View Source
@spec find_in_context(context(), atom() | String.t()) :: term()

Looks for a context value, taking care of some of the nasty details like fallback to :properties (a.k.a. custom context values) with support for both atom and string keys.

Specifically:

  1. If the key is a standard context key (either in its atom or string form), it looks for it in the standard context fields, without fallbacking to properties.
  2. Otherwise, it looks for it in properties, trying both the atomized and the stringified version of the key, starting from the supplied one.

NOTE that this can create atom at runtimes, which is dangerous. It is highly recommended you do not call this function with values from untrusted / unbounded sources.

Link to this macro

get_variant(feature_name_ast, opts_ast \\ [])

View Source (macro)

Returns the variant for the given feature flag.

See https://unleash.github.io/docs/beta_features#feature-toggle-variants

Takes a feature name and a set of options (in the form of a keyword list) that customise the behaviour of the feature check, see get_variant_opt/0 for the supported options and their defaults. The same constraints on options as enabled/2 apply, see its doc.

A special variant %{enabled: false, name: "disabled"} will be returned in any of these scenarios:

  • the feature flag is disabled
  • the feature flag does not define any variants
  • the feature flag does not exist and no fallback has been supplied

Examples

iex> Unleash.get_variant(:feature_a)
iex> Unleash.get_variant(:test, fallback: %{enabled: true, name: "variant_two"})
Link to this function

runtime_enabled?(feature_name, opts)

View Source
@spec runtime_enabled?(feature_name(), [enabled_opt()]) :: boolean() | nil

Runtime-friendly version of enabled?/2 with support for runtime option keys.

You are encouraged to use enabled?/2 whenever possible. Check its doc for more info.

Link to this function

runtime_get_variant(feature_name, opts)

View Source
@spec runtime_get_variant(feature_name(), get_variant_params()) ::
  Unleash.Variant.result() | nil

Runtime-friendly version of get_variant/2 with support for runtime option keys.

You are encouraged to use get_variant/2 whenever possible. Check its doc for more info.

Starts the Unleash SDK.

See Unleash for details.

Link to this function

stringify_context_key(atom_key)

View Source
@spec stringify_context_key(atom()) :: String.t()