Packages

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

Current section

Files

Jump to
elector src elector.erl
Raw

src/elector.erl

%%%-----------------------------------------------------------------------------
%% @doc This is the main API module.
%%
%% This module can be used to manually start new election or to check
%% if the current node is the leader. The `elector' application has
%% to be started before calling any of these functions. To start the
%% `elector' add it to your supervision tree or start it manually.
%%
%% When `elector' is started it will handle the elections automatically
%% startup and when new node joins/leaves erlang the cluster.
%% The elections are started automatically when new node joins the
%% cluster or old one leaves. It is possible to start an election
%% manually by calling `elector:elect/0' or `elect_sync/0'.
%%
%% See the README.md file for more information.
%% @end
%%%-----------------------------------------------------------------------------
-module(elector).
%%------------------------------------------------------------------------------
%% Exported API
%%------------------------------------------------------------------------------
-export([is_leader/0, elect/0, elect_sync/0, get_leader/0, clear_leader/0]).
%%------------------------------------------------------------------------------
%% Types
%%------------------------------------------------------------------------------
-type leader_node() :: node() | undefined.
%%------------------------------------------------------------------------------
%% Exported functions
%%------------------------------------------------------------------------------
%% @doc Returns boolean true this node is the leader or false if not.
-spec is_leader() -> {ok, boolean()} | {error, leader_node_not_set}.
is_leader() ->
LeaderNode = gen_server:call(elector_state, get_leader),
IsLeader = LeaderNode =:= node(),
if is_atom(LeaderNode) ->
{ok, IsLeader};
true ->
{error, leader_node_not_set}
end.
%% @doc Returns the current leader node's machine name.
-spec get_leader() -> {ok, node()} | {error, leader_node_not_set}.
get_leader() ->
LeaderNode = gen_server:call(elector_state, get_leader),
if is_atom(LeaderNode) ->
{ok, LeaderNode};
true ->
{error, leader_node_not_set}
end.
%% @doc Starts an election asynchronously.
-spec elect() ->
{ok, async_election_started} |
{error, quorum_size_not_met} |
{error, election_commission_not_up}.
elect() ->
CommissionPid = elector_service:commission_pid(),
QuorumRes = elector_config_handler:quorum_check(),
start_election(async, CommissionPid, QuorumRes).
%% @doc Starts an election synchronously.
-spec elect_sync() ->
{ok, leader_node()} |
{error, quorum_size_not_met} |
{error, election_commission_not_up}.
elect_sync() ->
CommissionPid = elector_service:commission_pid(),
QuorumRes = elector_config_handler:quorum_check(),
start_election(sync, CommissionPid, QuorumRes).
%% @doc Clears the leader node and sets it to undefined.
-spec clear_leader() -> {ok, leader_cleared}.
clear_leader() ->
gen_server:abcast([node() | nodes()], elector_state, clear_leader),
{ok, leader_cleared}.
%%------------------------------------------------------------------------------
%% Internal functions
%%------------------------------------------------------------------------------
%% @private
start_election(_Type, _CommissionPid, QuorumCheck) when QuorumCheck =:= false ->
{error, quorum_size_not_met};
start_election(_Type, CommissionPid, _QuorumCheck) when is_pid(CommissionPid) =:= false ->
{error, election_commission_not_up};
start_election(sync, CommissionPid, _QuorumCheck) ->
LeaderNode = gen_server:call(CommissionPid, start_election),
{ok, LeaderNode};
start_election(async, CommissionPid, _QuorumCheck) ->
gen_server:cast(CommissionPid, start_election),
{ok, async_election_started}.