Packages

Elects master node from Erlang/Elixir cluster that is agreed by all nodes.

Current section

Files

Jump to
elector src services elector_service.erl
Raw

src/services/elector_service.erl

%%%-----------------------------------------------------------------------------
%% @doc Module for handling the election process and internal API.
%% @private
%% @end
%%%-----------------------------------------------------------------------------
-module(elector_service).
-include("elector_header.hrl").
%%------------------------------------------------------------------------------
%% Exported API
%%------------------------------------------------------------------------------
-export([setup_election/1, hook_exec/3, commission_pid/0, async_call/2, iterate_hooks/2]).
%%------------------------------------------------------------------------------
%% Exported functions
%%------------------------------------------------------------------------------
commission_pid() ->
global:whereis_name(elector_commission).
async_call(Fun, Nodes) ->
Refs = [{Node, erpc:send_request(Node, Fun)} || Node <- Nodes],
[{Node, erpc:wait_response(Ref, ?ERPC_TIMEOUT)} || {Node, Ref} <- Refs].
setup_election(Opts) ->
pre_election(Opts),
LeaderNode = elector_strategy_behaviour:elect(),
gen_server:abcast([node() | nodes()], elector_state, {set_leader, LeaderNode}),
post_election(Opts),
LeaderNode.
hook_exec({M, F, A}, Caller, Ref) ->
erlang:apply(M, F, A),
Caller ! {hook_executed, Ref}.
iterate_hooks(_, false) ->
ok;
iterate_hooks([], _ExecuteHooks) ->
ok;
iterate_hooks([Mfa | Hooks], ExecuteHooks) when ExecuteHooks =:= true ->
Ref = erlang:make_ref(),
spawn(?MODULE, hook_exec, [Mfa, self(), Ref]),
receive
{hook_executed, Ref} ->
ok
after ?HOOK_EXEC_TIMEOUT ->
throw({error, hook_exec_timeout, Mfa})
end,
iterate_hooks(Hooks, ExecuteHooks).
%% @private
pre_election(#{run_hooks := ExecuteHooks} = _Opts) ->
Nodes = election_hook_nodes(),
Fun = fun() ->
elector_service:iterate_hooks(
elector_config_handler:pre_election_hooks(), ExecuteHooks)
end,
async_call(Fun, Nodes).
%% @private
post_election(#{run_hooks := ExecuteHooks} = _Opts) ->
Nodes = election_hook_nodes(),
Fun = fun() ->
elector_service:iterate_hooks(
elector_config_handler:post_election_hooks(), ExecuteHooks)
end,
async_call(Fun, Nodes).
%% @private
election_hook_nodes() ->
case elector_config_handler:hooks_execution() of
local ->
[node()];
global ->
[node() | nodes()]
end.