Packages
launchdarkly_server_sdk
2.1.2
3.11.0
3.10.1
3.9.0
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.0
3.5.0
3.4.0
3.3.1
3.3.0
3.2.0
3.1.0
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.1.2
2.1.1
2.1.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.3
1.1.2
1.1.1
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
1.0.0-beta4
retired
1.0.0-beta3
retired
1.0.0-beta2
retired
LaunchDarkly SDK for Erlang
Current section
Files
Jump to
Current section
Files
src/ldclient_instance.erl
%%-------------------------------------------------------------------
%% @doc `ldclient_instance' module
%% @private
%% @end
%%-------------------------------------------------------------------
-module(ldclient_instance).
%% API
-export([start/3]).
-export([stop/1]).
-export([stop_all/0]).
-export([update_processor_initialized/1]).
-export([feature_store_initialized/1]).
-type options() :: #{
base_uri => string(),
stream_uri => string(),
feature_store => atom(),
events_capacity => pos_integer(),
events_flush_interval => pos_integer(),
events_dispatcher => atom(),
context_keys_capacity => pos_integer(),
private_attributes => ldclient_config:private_attributes(),
stream => boolean(),
polling_interval => pos_integer(),
polling_update_requestor => atom(),
offline => boolean(),
redis_host => string(),
redis_port => pos_integer(),
redis_database => integer(),
redis_password => string(),
redis_prefix => string(),
redis_tls => [ssl:tls_option()] | undefined,
use_ldd => boolean(),
cache_ttl => integer(),
send_events => boolean(),
file_datasource => boolean(),
file_paths => [string()],
file_auto_update => boolean(),
file_poll_interval => pos_integer(),
file_allow_duplicate_keys => boolean(),
http_options => ldclient_config:http_options(),
testdata_tag => atom(),
datasource => atom()
}.
%% Options for starting an SDK instance
-export_type([options/0]).
%%===================================================================
%% API
%%===================================================================
%% @doc Start a client instance
%%
%% @end
-spec start(Tag :: atom(), SdkKey :: string(), Options :: options()) ->
ok | {error, already_started, term()}.
start(Tag, SdkKey, Options) ->
% TODO check if Tag already exists and return already_started error
% Parse options into settings
Settings = ldclient_config:parse_options(SdkKey, Options),
ok = ldclient_config:register(Tag, Settings),
% Start instance supervisor
SupName = get_ref_from_tag(instance, Tag),
UpdateSupName = get_ref_from_tag(instance_stream, Tag),
UpdateWorkerModule = get_update_processor(Settings),
EventsSupName = get_ref_from_tag(instance_events, Tag),
{ok, _} = supervisor:start_child(ldclient_sup, ldclient_instance_sup:child_spec(SupName, [SupName, UpdateSupName, UpdateWorkerModule, EventsSupName, Tag])),
% Start storage backend
true = ldclient_update_processor_state:create_storage_initialized_state(Tag, false),
FeatureStore = maps:get(feature_store, Settings),
ok = FeatureStore:init(SupName, Tag, []),
% Start stream client
true = ldclient_update_processor_state:create_initialized_state(Tag, false),
start_updater(UpdateSupName, UpdateWorkerModule, Tag).
%% @doc Stop a client instance
%%
%% @end
-spec stop(Tag :: atom()) -> ok.
stop(Tag) when is_atom(Tag) ->
% TODO only stop stream instance if it's running
% Terminate stream
StreamSupName = get_ref_from_tag(instance_stream, Tag),
ok = ldclient_updater:stop(StreamSupName),
% Terminate storage
FeatureStore = ldclient_config:get_value(Tag, feature_store),
ok = FeatureStore:terminate(Tag),
% Terminate instance supervisors
SupName = get_ref_from_tag(instance, Tag),
ok = supervisor:terminate_child(ldclient_sup, SupName),
ok = supervisor:delete_child(ldclient_sup, SupName),
ldclient_update_processor_state:delete_initialized_state(Tag),
ldclient_update_processor_state:delete_storage_initialized_state(Tag),
ldclient_config:unregister(Tag).
%% @doc Stop all client instances
%%
%% @end
-spec stop_all() -> ok.
stop_all() ->
Tags = ldclient_config:get_registered_tags(),
lists:foreach(fun stop/1, Tags).
%% @doc Whether an instance's update processor has initialized
%%
%% @end
-spec update_processor_initialized(Tag :: atom()) -> boolean().
update_processor_initialized(Tag) ->
ldclient_update_processor_state:get_initialized_state(Tag).
%% @doc Whether an instance's feature store has initialized
%%
%% @end
-spec feature_store_initialized(Tag :: atom()) -> boolean().
feature_store_initialized(Tag) ->
ldclient_update_processor_state:get_storage_initialized_state(Tag).
%%===================================================================
%% Internal functions
%%===================================================================
%% @doc Get a supervisor registration name for a given tag
%% @private
%%
%% @end
-spec get_ref_from_tag(atom(), Tag :: atom()) -> atom().
get_ref_from_tag(instance, Tag) when is_atom(Tag) ->
list_to_atom("ldclient_instance_" ++ atom_to_list(Tag));
get_ref_from_tag(instance_stream, Tag) when is_atom(Tag) ->
list_to_atom("ldclient_instance_stream_" ++ atom_to_list(Tag));
get_ref_from_tag(instance_events, Tag) when is_atom(Tag) ->
list_to_atom("ldclient_instance_events_" ++ atom_to_list(Tag)).
%% @doc Initialize update processor client and start listening
%% @private
%%
%% @end
-spec start_updater(atom(), atom(), atom()) ->
ok.
start_updater(UpdateSupName, UpdateWorkerModule, Tag) ->
{ok, _Pid} = ldclient_updater:start(UpdateSupName, UpdateWorkerModule, Tag),
ok.
%% @doc Get update processor module name depending on settings
%% @private
%%
%% @end
-spec get_update_processor(Settings :: #{ stream := boolean(),
offline := boolean(),
use_ldd := boolean(),
file_datasource := boolean(),
datasource := atom(),
_ => _
}) -> atom().
get_update_processor(#{ offline := true }) ->
ldclient_update_null_server;
get_update_processor(#{ use_ldd := true }) ->
ldclient_update_null_server;
get_update_processor(#{ datasource := DataSource }) when DataSource /= undefined ->
list_to_atom("ldclient_update_" ++ atom_to_list(DataSource) ++ "_server");
get_update_processor(#{ file_datasource := true }) ->
ldclient_update_file_server;
get_update_processor(#{ stream := false }) ->
ldclient_update_poll_server;
get_update_processor(#{ stream := true }) ->
ldclient_update_stream_server.