From a743ce0f4b5c7d2ee399772c4af93c7a363f69e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 26 Mar 2025 15:16:04 +0100 Subject: [PATCH] ra: Add `aux_command/3` This is the same as `aux_command/2` but it takes a timeout as its third argument. --- src/ra.erl | 10 ++++++++++ test/ra_machine_int_SUITE.erl | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/ra.erl b/src/ra.erl index 7296c7202..92a594a09 100644 --- a/src/ra.erl +++ b/src/ra.erl @@ -77,6 +77,7 @@ transfer_leadership/2, %% auxiliary commands aux_command/2, + aux_command/3, cast_aux_command/2, register_external_log_reader/1, member_overview/1, @@ -1172,6 +1173,15 @@ transfer_leadership(ServerId, TargetServerId) -> aux_command(ServerRef, Cmd) -> gen_statem:call(ServerRef, {aux_command, Cmd}). +%% @doc Executes (using a call) an auxiliary command that the state machine can handle. +%% +%% @param ServerId the Ra server(s) to send the query to +%% @param Command an arbitrary term that the state machine can handle +%% @end +-spec aux_command(ra_server_id(), term(), timeout()) -> term(). +aux_command(ServerRef, Cmd, Timeout) -> + gen_statem:call(ServerRef, {aux_command, Cmd}, Timeout). + %% @doc Executes (using a cast) an auxiliary command that the state machine can handle. %% %% @param ServerId the Ra server(s) to send the query to diff --git a/test/ra_machine_int_SUITE.erl b/test/ra_machine_int_SUITE.erl index 183209bd8..0d74b0f8d 100644 --- a/test/ra_machine_int_SUITE.erl +++ b/test/ra_machine_int_SUITE.erl @@ -51,6 +51,7 @@ all_tests() -> aux_command, aux_command_v2, aux_command_v1_and_v2, + aux_command_timeout, aux_monitor_effect, aux_and_machine_monitor_same_process, aux_and_machine_monitor_same_node, @@ -810,6 +811,37 @@ aux_command_v1_and_v2(Config) -> ra:delete_cluster(Cluster), ok. +aux_command_timeout(Config) -> + ClusterName = ?config(cluster_name, Config), + ServerId1 = ?config(server_id, Config), + Cluster = [ServerId1, + ?config(server_id2, Config), + ?config(server_id3, Config)], + Mod = ?config(modname, Config), + meck:new(Mod, [non_strict]), + meck:expect(Mod, init, fun (_) -> [] end), + meck:expect(Mod, init_aux, fun (_) -> undefined end), + meck:expect(Mod, apply, + fun + (_, Cmd, State) -> + ct:pal("handling ~p", [Cmd]), + %% handle all + {State, ok} + end), + meck:expect(Mod, handle_aux, + fun + (_RaftState, {call, _From}, {sleep, Sleep}, AuxState, Opaque) -> + timer:sleep(Sleep), + {reply, ok, AuxState, Opaque}; + (_RaftState, cast, _Msg, AuxState, Opaque) -> + {no_reply, AuxState, Opaque} + end), + ok = start_cluster(ClusterName, {module, Mod, #{}}, Cluster), + ?assertEqual(ok, ra:aux_command(ServerId1, {sleep, 100}, 500)), + ?assertExit({timeout, _}, ra:aux_command(ServerId1, {sleep, 1000}, 500)), + ra:delete_cluster(Cluster), + ok. + aux_eval(Config) -> %% aux handle is automatically passed an eval command after new entries %% have been applied