Current section
Files
Jump to
Current section
Files
src/evoq_decisions_sup.erl
%% @doc Supervisor for the stateful decision-actor subsystem (Part B).
%%
%% Mirrors evoq_aggregates_sup: the decision registry plus N partition
%% supervisors, with actors distributed by phash2({Module, Key}, N).
%% A separate tree from the aggregate one — no shared, hardwired sup is
%% touched (see SPIKE_EVOQ_DECISION_ACTOR.md, Path 1).
%%
%% @author rgfaber
-module(evoq_decisions_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([start_decision/3, partition_for/1]).
%% Supervisor callbacks
-export([init/1]).
-define(NUM_PARTITIONS, 4).
%%====================================================================
%% API
%%====================================================================
%% @doc Start the decisions supervisor.
-spec start_link() -> {ok, pid()} | {error, term()}.
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% @doc Start a decision actor for {Module, Key} in its partition.
-spec start_decision(module(), binary(), atom()) ->
{ok, pid()} | {error, term()}.
start_decision(Module, Key, StoreId) ->
Partition = partition_for({Module, Key}),
PartitionSup = partition_sup_name(Partition),
supervisor:start_child(PartitionSup, [Module, Key, StoreId]).
%% @doc Partition for a {Module, Key} boundary identity.
-spec partition_for({module(), binary()}) -> 1..?NUM_PARTITIONS.
partition_for(BoundaryId) ->
erlang:phash2(BoundaryId, ?NUM_PARTITIONS) + 1.
%%====================================================================
%% Supervisor callbacks
%%====================================================================
%% @private
init([]) ->
SupFlags = #{
strategy => one_for_one,
intensity => 10,
period => 60
},
Registry = #{
id => evoq_decision_registry,
start => {evoq_decision_registry, start_link, []},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [evoq_decision_registry]
},
PartitionSups = [partition_sup_spec(N) || N <- lists:seq(1, ?NUM_PARTITIONS)],
{ok, {SupFlags, [Registry | PartitionSups]}}.
%%====================================================================
%% Internal
%%====================================================================
partition_sup_name(N) ->
list_to_atom("evoq_decision_partition_sup_" ++ integer_to_list(N)).
partition_sup_spec(N) ->
Name = partition_sup_name(N),
#{
id => Name,
start => {evoq_decision_partition_sup, start_link, [Name]},
restart => permanent,
shutdown => infinity,
type => supervisor,
modules => [evoq_decision_partition_sup]
}.