Current section

Files

Jump to
flagship lib feature_flags.ex
Raw

lib/feature_flags.ex

defmodule Flagship.FeatureFlags do
@moduledoc false
use GenServer
alias Flagship.LaunchDarkly
require Logger
@check_ms 500
def start_link(opts) do
GenServer.start_link(__MODULE__, :ok, opts)
end
@doc """
Gets a feature flag value (or fallback) for the given flag key and context
## Examples
iex> Flagship.FeatureFlags.get("flag_name", false)
true
Flag not set, and fallback is true
iex> Flagship.FeatureFlags.get("flag_name", true)
true
The context can be sent as:
a string, in which case it will be treated as a user key.
a map, in which case it will be treated as a context object.
or not at all, in which case it will be treated as a default context.
* for information on setting the default context, see the README
## Examples
iex> Flagship.FeatureFlags.get("flag_name", false, "user_key")
true
iex> Flag.FeatureFlags.get("flag_name", false, %{:kind => "location", :key => location_code})
true
"""
def get(key, fallback) do
GenServer.call(__MODULE__, {:get, key, fallback, default_context()})
end
def get(key, fallback, context) when is_map(context) do
GenServer.call(__MODULE__, {:get, key, fallback, context})
end
def get(key, fallback, user_key) do
GenServer.call(__MODULE__, {:get, key, fallback, %{:kind => "user", :key => user_key}})
end
@doc """
Reports details about a LaunchDarkly user or context
## Examples
iex> Flagship.FeatureFlags.identify(%{:key => "user_key", :country => "US"})
:ok
"""
def identify(user) do
GenServer.call(__MODULE__, {:identify, user})
end
@doc """
Creates a new LaunchDarkly user
## Examples
iex> Flagship.FeatureFlags.new_user(%{:key => "user_key", :country => "US"})
%{:key => "user_key", :ip => "" :country => "US", :email => "foo@bar.baz", :first_name => "Foo", :last_name => "Bar", :avatar => "http://www.gravatar.com/avatar/1", :name => "Foo Bar", :anonymous => false, :custom => %{}, :private_attribute_names => []}
"""
def new_user(user_map) do
GenServer.call(__MODULE__, {:new_user, user_map})
end
@doc """
Stops all LaunchDarkly client instances
## Examples
iex> Flagship.FeatureFlags.stop_all_instances()
:ok
"""
def stop_all_instances() do
GenServer.call(__MODULE__, {:stop_all_instances})
end
@doc false
def init(:ok) do
ldclient_options = Application.get_env(:flagship, :ld_client_options, %{})
launch_darkly_sdk_key = Application.get_env(:flagship, :ld_sdk_key)
LaunchDarkly.start_instance(launch_darkly_sdk_key, ldclient_options)
wait_for_initialization()
{:ok, %{}}
end
def terminate(_reason, _state) do
stop_all_instances()
:normal
end
def track(event_name, context, data, tag \\ nil) do
GenServer.call(__MODULE__, {:track, event_name, context, data, tag})
end
@doc false
def handle_call({:get, key, fallback, context}, from, state) do
Logger.info(
"Looking up value for LaunchDarkly flag: #{key} with context: #{inspect(context)} from: #{inspect(from)}}"
)
{:reply, LaunchDarkly.variation(key, context, fallback), state}
end
@doc false
def handle_call({:identify, user}, from, state) do
Logger.info("Identifying LaunchDarkly user: #{inspect(user)} from: #{inspect(from)}}")
{:reply, LaunchDarkly.identify(user), state}
end
@doc false
def handle_call({:stop_all_instances}, from, state) do
Logger.info("Stopping all LaunchDarkly client instances from: #{inspect(from)}")
{:reply, LaunchDarkly.stop_all_instances(), state}
end
@doc false
def handle_call({:new_user, user_map}, from, state) do
Logger.info("Creating a LaunchDarkly user: #{inspect(user_map)} from: #{inspect(from)}}")
{:reply, LaunchDarkly.new_user(user_map), state}
end
@doc false
def handle_call({:track, event_name, context, data, tag}, from, state) do
Logger.info(
"Tracking LaunchDarkly event: #{inspect(event_name)} with context: #{inspect(context)} and data: #{inspect(data)} with tag: #{tag}"
)
Task.async(LaunchDarkly, :track, [event_name, context, data, tag])
{:reply, :ok, state}
end
def handle_info(:wait_for_initialization, state) do
wait_for_initialization()
{:noreply, state}
end
def initialized? do
LaunchDarkly.initialized(:default)
end
defp wait_for_initialization() do
Logger.info("Waiting for LaunchDarkly flag data...")
if Flagship.FeatureFlags.initialized?() do
Logger.info("LaunchDarkly flag data is ready.")
:initialized
else
Process.send_after(self(), :wait_for_initialization, @check_ms)
end
end
defp default_context do
Application.get_env(:flagship, :default_context, %{})
end
end