Skip to content

Commit

Permalink
feat: add singleton strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
thalesmg committed Jun 13, 2024
1 parent cd2877b commit 41618f3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/ekka_autocluster.erl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enabled() ->
configured() ->
case ekka:env(cluster_discovery) of
{ok, {manual, _}} -> false;
{ok, {singleton, _}} -> false;
{ok, _Strategy} -> true;
undefined -> false
end.
Expand Down Expand Up @@ -96,6 +97,8 @@ core_node_discovery_callback() ->
case ekka:env(cluster_discovery) of
{ok, {manual, _}} ->
[];
{ok, {singleton, _}} ->
[];
{ok, {Strategy, Options}} ->
Mod = strategy_module(Strategy),
try ekka_cluster_strategy:discover(Mod, Options) of
Expand Down Expand Up @@ -197,6 +200,8 @@ with_strategy(Fun) ->
case ekka:env(cluster_discovery) of
{ok, {manual, _}} ->
ignore;
{ok, {singleton, _}} ->
ignore;
{ok, {Strategy, Options}} ->
Fun(strategy_module(Strategy), Options);
undefined ->
Expand Down
29 changes: 28 additions & 1 deletion src/ekka_cluster.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
, leave/0
, force_leave/1
, status/1
, is_singleton/0
, is_singleton/1
]).

-type(info_key() :: running_nodes | stopped_nodes).
Expand All @@ -50,7 +52,12 @@ status(Node) ->
%% @doc Join the cluster
-spec(join(node()) -> ok | ignore | {error, term()}).
join(Node) ->
mria:join(Node).
case is_singleton() orelse is_singleton(Node) of
true ->
{error, singleton};
false ->
mria:join(Node)
end.

%% @doc Leave from the cluster.
-spec(leave() -> ok | {error, any()}).
Expand All @@ -61,3 +68,23 @@ leave() ->
-spec(force_leave(node()) -> ok | ignore | {error, term()}).
force_leave(Node) ->
mria:force_leave(Node).

-spec is_singleton() -> boolean().
is_singleton() ->
case ekka:env(cluster_discovery) of
{ok, {singleton, _}} ->
true;
_ ->
false
end.

-spec is_singleton(node()) -> boolean().
is_singleton(Node) when Node =:= node() ->
is_singleton();
is_singleton(Node) ->
try
erpc:call(Node, ?MODULE, is_singleton, [])
catch
_:_ ->
false
end.
27 changes: 27 additions & 0 deletions test/ekka_autocluster_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
{suffix, ""}
]).

-define(ON(NODE, BODY), erpc:call(NODE, fun() -> BODY end)).

all() -> ekka_ct:all(?MODULE).

%%--------------------------------------------------------------------
Expand Down Expand Up @@ -330,6 +332,31 @@ t_core_node_discovery_callback(Config) ->
),
ok.

%%--------------------------------------------------------------------
%% "Autocluster" via 'singleton' strategy

t_singleton(_Config) ->
N1 = ekka_ct:start_slave(ekka, n1),
N2 = ekka_ct:start_slave(ekka, n2),
try
ok = ekka_ct:wait_running(N1),
ok = ekka_ct:wait_running(N2),
ok = set_app_env(N1, {singleton, []}),
ok = set_app_env(N2, {static, [{seeds, []}]}),
?ON(N1, ?assertMatch({error, singleton}, ekka:join(N2))),
%% Other nodes must not join the singleton.
?ON(N2, ?assertMatch({error, singleton}, ekka:join(N1))),
?ON(N1, ?assertNot(ekka:autocluster_enabled())),
?ON(N1, ?assertNot(ekka_autocluster:configured())),
?ON(N1, ?assertNot(ekka_autocluster:enabled())),
?ON(N1, ?assertEqual(ignore, ekka_autocluster:run(myapp))),
?ON(N1, ?assertEqual(ignore, ekka_autocluster:unregister_node())),
?ON(N1, ?assertEqual([], ekka_autocluster:core_node_discovery_callback())),
ok
after
ok = ekka_ct:stop_slave(N1)
end.

%%--------------------------------------------------------------------
%% Misc tests
%%--------------------------------------------------------------------
Expand Down

0 comments on commit 41618f3

Please sign in to comment.