feat: emqx_resource support cluster_call
This commit is contained in:
parent
4528508620
commit
73238ed81f
|
@ -89,7 +89,7 @@ headers(_) -> undefined.
|
||||||
headers_no_content_type(type) -> map();
|
headers_no_content_type(type) -> map();
|
||||||
headers_no_content_type(converter) ->
|
headers_no_content_type(converter) ->
|
||||||
fun(Headers) ->
|
fun(Headers) ->
|
||||||
maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
|
maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
|
||||||
end;
|
end;
|
||||||
headers_no_content_type(default) -> default_headers_no_content_type();
|
headers_no_content_type(default) -> default_headers_no_content_type();
|
||||||
headers_no_content_type(_) -> undefined.
|
headers_no_content_type(_) -> undefined.
|
||||||
|
@ -129,9 +129,9 @@ create(#{ method := Method
|
||||||
emqx_connector_http,
|
emqx_connector_http,
|
||||||
Config#{base_url => maps:remove(query, URIMap),
|
Config#{base_url => maps:remove(query, URIMap),
|
||||||
pool_type => random}) of
|
pool_type => random}) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
@ -296,4 +296,4 @@ parse_body(<<"application/json">>, Body) ->
|
||||||
parse_body(<<"application/x-www-form-urlencoded">>, Body) ->
|
parse_body(<<"application/x-www-form-urlencoded">>, Body) ->
|
||||||
{ok, maps:from_list(cow_qs:parse_qs(Body))};
|
{ok, maps:from_list(cow_qs:parse_qs(Body))};
|
||||||
parse_body(ContentType, _) ->
|
parse_body(ContentType, _) ->
|
||||||
{error, {unsupported_content_type, ContentType}}.
|
{error, {unsupported_content_type, ContentType}}.
|
||||||
|
|
|
@ -106,9 +106,9 @@ create(#{ selector := Selector
|
||||||
, '_unique'], Config),
|
, '_unique'], Config),
|
||||||
NState = State#{selector => NSelector},
|
NState = State#{selector => NSelector},
|
||||||
case emqx_resource:create_local(Unique, emqx_connector_mongo, Config) of
|
case emqx_resource:create_local(Unique, emqx_connector_mongo, Config) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
{ok, NState};
|
{ok, NState};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
{ok, NState};
|
{ok, NState};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
|
|
@ -83,9 +83,9 @@ create(#{ password_hash_algorithm := Algorithm
|
||||||
query_timeout => QueryTimeout,
|
query_timeout => QueryTimeout,
|
||||||
'_unique' => Unique},
|
'_unique' => Unique},
|
||||||
case emqx_resource:create_local(Unique, emqx_connector_mysql, Config) of
|
case emqx_resource:create_local(Unique, emqx_connector_mysql, Config) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
@ -131,7 +131,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
destroy(#{'_unique' := Unique}) ->
|
destroy(#{'_unique' := Unique}) ->
|
||||||
_ = emqx_resource:remove_local(Unique),
|
_ = emqx_resource:remove_local(Unique),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
|
@ -71,9 +71,9 @@ create(#{ query := Query0
|
||||||
salt_position => SaltPosition,
|
salt_position => SaltPosition,
|
||||||
'_unique' => Unique},
|
'_unique' => Unique},
|
||||||
case emqx_resource:create_local(Unique, emqx_connector_pgsql, Config) of
|
case emqx_resource:create_local(Unique, emqx_connector_pgsql, Config) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
{ok, State};
|
{ok, State};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
@ -119,7 +119,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
destroy(#{'_unique' := Unique}) ->
|
destroy(#{'_unique' := Unique}) ->
|
||||||
_ = emqx_resource:remove_local(Unique),
|
_ = emqx_resource:remove_local(Unique),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
|
@ -89,9 +89,9 @@ create(#{ query := Query
|
||||||
, '_unique'], Config),
|
, '_unique'], Config),
|
||||||
NState = State#{query => NQuery},
|
NState = State#{query => NQuery},
|
||||||
case emqx_resource:create_local(Unique, emqx_connector_redis, Config) of
|
case emqx_resource:create_local(Unique, emqx_connector_redis, Config) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
{ok, NState};
|
{ok, NState};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
{ok, NState};
|
{ok, NState};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
@ -176,7 +176,7 @@ check_fields(["superuser" | More], HasPassHash) ->
|
||||||
check_fields(More, HasPassHash);
|
check_fields(More, HasPassHash);
|
||||||
check_fields([Field | _], _) ->
|
check_fields([Field | _], _) ->
|
||||||
error({unsupported_field, Field}).
|
error({unsupported_field, Field}).
|
||||||
|
|
||||||
parse_key(Key) ->
|
parse_key(Key) ->
|
||||||
Tokens = re:split(Key, "(" ++ ?RE_PLACEHOLDER ++ ")", [{return, binary}, group, trim]),
|
Tokens = re:split(Key, "(" ++ ?RE_PLACEHOLDER ++ ")", [{return, binary}, group, trim]),
|
||||||
parse_key(Tokens, []).
|
parse_key(Tokens, []).
|
||||||
|
|
|
@ -216,8 +216,8 @@ create_resource(#{type := DB,
|
||||||
Config,
|
Config,
|
||||||
[])
|
[])
|
||||||
of
|
of
|
||||||
|
{ok, already_created} -> ResourceID;
|
||||||
{ok, _} -> ResourceID;
|
{ok, _} -> ResourceID;
|
||||||
{error, already_created} -> ResourceID;
|
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} -> {error, Reason}
|
||||||
end;
|
end;
|
||||||
create_resource(#{type := DB,
|
create_resource(#{type := DB,
|
||||||
|
@ -228,8 +228,8 @@ create_resource(#{type := DB,
|
||||||
list_to_existing_atom(io_lib:format("~s_~s",[emqx_connector, DB])),
|
list_to_existing_atom(io_lib:format("~s_~s",[emqx_connector, DB])),
|
||||||
Config)
|
Config)
|
||||||
of
|
of
|
||||||
|
{ok, already_created} -> ResourceID;
|
||||||
{ok, _} -> ResourceID;
|
{ok, _} -> ResourceID;
|
||||||
{error, already_created} -> ResourceID;
|
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} -> {error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -77,10 +77,10 @@ create_bridge(#{name := Name}, Params) ->
|
||||||
case emqx_resource:check_and_create(
|
case emqx_resource:check_and_create(
|
||||||
emqx_data_bridge:name_to_resource_id(Name),
|
emqx_data_bridge:name_to_resource_id(Name),
|
||||||
emqx_data_bridge:resource_type(atom(BridgeType)), maps:from_list(Config)) of
|
emqx_data_bridge:resource_type(atom(BridgeType)), maps:from_list(Config)) of
|
||||||
|
{ok, already_created} ->
|
||||||
|
{400, #{code => 102, message => <<"bridge already created: ", Name/binary>>}};
|
||||||
{ok, Data} ->
|
{ok, Data} ->
|
||||||
update_config_and_reply(Name, BridgeType, Config, Data);
|
update_config_and_reply(Name, BridgeType, Config, Data);
|
||||||
{error, already_created} ->
|
|
||||||
{400, #{code => 102, message => <<"bridge already created: ", Name/binary>>}};
|
|
||||||
{error, Reason0} ->
|
{error, Reason0} ->
|
||||||
Reason = emqx_resource_api:stringnify(Reason0),
|
Reason = emqx_resource_api:stringnify(Reason0),
|
||||||
{500, #{code => 102, message => <<"create bridge ", Name/binary,
|
{500, #{code => 102, message => <<"create bridge ", Name/binary,
|
||||||
|
|
|
@ -73,8 +73,8 @@ load_bridge(#{name := Name, type := Type, config := Config}) ->
|
||||||
case emqx_resource:create_local(
|
case emqx_resource:create_local(
|
||||||
emqx_data_bridge:name_to_resource_id(Name),
|
emqx_data_bridge:name_to_resource_id(Name),
|
||||||
emqx_data_bridge:resource_type(Type), Config) of
|
emqx_data_bridge:resource_type(Type), Config) of
|
||||||
|
{ok, already_created} -> ok;
|
||||||
{ok, _} -> ok;
|
{ok, _} -> ok;
|
||||||
{error, already_created} -> ok;
|
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
error({load_bridge, Reason})
|
error({load_bridge, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -130,8 +130,8 @@ handle_call(reset, _From, State) ->
|
||||||
|
|
||||||
handle_call({initiate, MFA}, _From, State = #{node := Node}) ->
|
handle_call({initiate, MFA}, _From, State = #{node := Node}) ->
|
||||||
case transaction(fun init_mfa/2, [Node, MFA]) of
|
case transaction(fun init_mfa/2, [Node, MFA]) of
|
||||||
{atomic, {ok, TnxId}} ->
|
{atomic, {ok, TnxId, Result}} ->
|
||||||
{reply, {ok, TnxId}, State, {continue, ?CATCH_UP}};
|
{reply, {ok, TnxId, Result}, State, {continue, ?CATCH_UP}};
|
||||||
{aborted, Reason} ->
|
{aborted, Reason} ->
|
||||||
{reply, {error, Reason}, State, {continue, ?CATCH_UP}}
|
{reply, {error, Reason}, State, {continue, ?CATCH_UP}}
|
||||||
end;
|
end;
|
||||||
|
@ -159,8 +159,9 @@ catch_up(#{node := Node, retry_interval := RetryMs} = State) ->
|
||||||
case transaction(fun get_next_mfa/1, [Node]) of
|
case transaction(fun get_next_mfa/1, [Node]) of
|
||||||
{atomic, caught_up} -> ?TIMEOUT;
|
{atomic, caught_up} -> ?TIMEOUT;
|
||||||
{atomic, {still_lagging, NextId, MFA}} ->
|
{atomic, {still_lagging, NextId, MFA}} ->
|
||||||
case apply_mfa(NextId, MFA) of
|
{Succeed, _} = apply_mfa(NextId, MFA),
|
||||||
ok ->
|
case Succeed of
|
||||||
|
true ->
|
||||||
case transaction(fun commit/2, [Node, NextId]) of
|
case transaction(fun commit/2, [Node, NextId]) of
|
||||||
{atomic, ok} -> catch_up(State);
|
{atomic, ok} -> catch_up(State);
|
||||||
Error ->
|
Error ->
|
||||||
|
@ -171,7 +172,7 @@ catch_up(#{node := Node, retry_interval := RetryMs} = State) ->
|
||||||
error => Error}),
|
error => Error}),
|
||||||
RetryMs
|
RetryMs
|
||||||
end;
|
end;
|
||||||
_Error -> RetryMs
|
false -> RetryMs
|
||||||
end;
|
end;
|
||||||
{aborted, Reason} ->
|
{aborted, Reason} ->
|
||||||
?SLOG(error, #{
|
?SLOG(error, #{
|
||||||
|
@ -209,9 +210,8 @@ do_catch_up(ToTnxId, Node) ->
|
||||||
CurTnxId = LastAppliedId + 1,
|
CurTnxId = LastAppliedId + 1,
|
||||||
[#cluster_rpc_mfa{mfa = MFA}] = mnesia:read(?CLUSTER_MFA, CurTnxId),
|
[#cluster_rpc_mfa{mfa = MFA}] = mnesia:read(?CLUSTER_MFA, CurTnxId),
|
||||||
case apply_mfa(CurTnxId, MFA) of
|
case apply_mfa(CurTnxId, MFA) of
|
||||||
ok -> ok = commit(Node, CurTnxId);
|
{true, _Result} -> ok = commit(Node, CurTnxId);
|
||||||
{error, Reason} -> mnesia:abort(Reason);
|
{false, Error} -> mnesia:abort(Error)
|
||||||
Other -> mnesia:abort(Other)
|
|
||||||
end;
|
end;
|
||||||
[#cluster_rpc_commit{tnx_id = LastAppliedId}] ->
|
[#cluster_rpc_commit{tnx_id = LastAppliedId}] ->
|
||||||
Reason = lists:flatten(io_lib:format("~p catch up failed by LastAppliedId(~p) > ToTnxId(~p)",
|
Reason = lists:flatten(io_lib:format("~p catch up failed by LastAppliedId(~p) > ToTnxId(~p)",
|
||||||
|
@ -243,9 +243,8 @@ init_mfa(Node, MFA) ->
|
||||||
ok = mnesia:write(?CLUSTER_MFA, MFARec, write),
|
ok = mnesia:write(?CLUSTER_MFA, MFARec, write),
|
||||||
ok = commit(Node, TnxId),
|
ok = commit(Node, TnxId),
|
||||||
case apply_mfa(TnxId, MFA) of
|
case apply_mfa(TnxId, MFA) of
|
||||||
ok -> {ok, TnxId};
|
{true, Result} -> {ok, TnxId, Result};
|
||||||
{error, Reason} -> mnesia:abort(Reason);
|
{false, Error} -> mnesia:abort(Error)
|
||||||
Other -> mnesia:abort(Other)
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_catch_up_in_one_trans(LatestId, Node) ->
|
do_catch_up_in_one_trans(LatestId, Node) ->
|
||||||
|
@ -284,15 +283,21 @@ trans_query(TnxId) ->
|
||||||
apply_mfa(TnxId, {M, F, A} = MFA) ->
|
apply_mfa(TnxId, {M, F, A} = MFA) ->
|
||||||
try
|
try
|
||||||
Res = erlang:apply(M, F, A),
|
Res = erlang:apply(M, F, A),
|
||||||
case Res =:= ok of
|
Succeed =
|
||||||
true ->
|
case Res of
|
||||||
?SLOG(notice, #{msg => "succeeded to apply MFA", tnx_id => TnxId, mfa => MFA, result => ok});
|
ok ->
|
||||||
false ->
|
?SLOG(notice, #{msg => "succeeded to apply MFA", tnx_id => TnxId, mfa => MFA, result => Res}),
|
||||||
?SLOG(error, #{msg => "failed to apply MFA", tnx_id => TnxId, mfa => MFA, result => Res})
|
true;
|
||||||
|
{ok, _} ->
|
||||||
|
?SLOG(notice, #{msg => "succeeded to apply MFA", tnx_id => TnxId, mfa => MFA, result => Res}),
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
?SLOG(error, #{msg => "failed to apply MFA", tnx_id => TnxId, mfa => MFA, result => Res}),
|
||||||
|
false
|
||||||
end,
|
end,
|
||||||
Res
|
{Succeed, Res}
|
||||||
catch
|
catch
|
||||||
C : E ->
|
C : E ->
|
||||||
?SLOG(critical, #{msg => "crash to apply MFA", tnx_id => TnxId, mfa => MFA, exception => C, reason => E}),
|
?SLOG(critical, #{msg => "crash to apply MFA", tnx_id => TnxId, mfa => MFA, exception => C, reason => E}),
|
||||||
{error, lists:flatten(io_lib:format("TnxId(~p) apply MFA(~p) crash", [TnxId, MFA]))}
|
{false, lists:flatten(io_lib:format("TnxId(~p) apply MFA(~p) crash", [TnxId, MFA]))}
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -72,7 +72,7 @@ t_base_test(_Config) ->
|
||||||
?assertEqual(emqx_cluster_rpc:status(), {atomic, []}),
|
?assertEqual(emqx_cluster_rpc:status(), {atomic, []}),
|
||||||
Pid = self(),
|
Pid = self(),
|
||||||
MFA = {M, F, A} = {?MODULE, echo, [Pid, test]},
|
MFA = {M, F, A} = {?MODULE, echo, [Pid, test]},
|
||||||
{ok, TnxId} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, TnxId, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
{atomic, Query} = emqx_cluster_rpc:query(TnxId),
|
{atomic, Query} = emqx_cluster_rpc:query(TnxId),
|
||||||
?assertEqual(MFA, maps:get(mfa, Query)),
|
?assertEqual(MFA, maps:get(mfa, Query)),
|
||||||
?assertEqual(node(), maps:get(initiator, Query)),
|
?assertEqual(node(), maps:get(initiator, Query)),
|
||||||
|
@ -105,7 +105,7 @@ t_commit_ok_but_apply_fail_on_other_node(_Config) ->
|
||||||
emqx_cluster_rpc:reset(),
|
emqx_cluster_rpc:reset(),
|
||||||
{atomic, []} = emqx_cluster_rpc:status(),
|
{atomic, []} = emqx_cluster_rpc:status(),
|
||||||
MFA = {M, F, A} = {?MODULE, failed_on_node, [erlang:whereis(?NODE1)]},
|
MFA = {M, F, A} = {?MODULE, failed_on_node, [erlang:whereis(?NODE1)]},
|
||||||
{ok, _} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, _, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
{atomic, [Status]} = emqx_cluster_rpc:status(),
|
{atomic, [Status]} = emqx_cluster_rpc:status(),
|
||||||
?assertEqual(MFA, maps:get(mfa, Status)),
|
?assertEqual(MFA, maps:get(mfa, Status)),
|
||||||
?assertEqual(node(), maps:get(node, Status)),
|
?assertEqual(node(), maps:get(node, Status)),
|
||||||
|
@ -118,7 +118,7 @@ t_catch_up_status_handle_next_commit(_Config) ->
|
||||||
emqx_cluster_rpc:reset(),
|
emqx_cluster_rpc:reset(),
|
||||||
{atomic, []} = emqx_cluster_rpc:status(),
|
{atomic, []} = emqx_cluster_rpc:status(),
|
||||||
{M, F, A} = {?MODULE, failed_on_node_by_odd, [erlang:whereis(?NODE1)]},
|
{M, F, A} = {?MODULE, failed_on_node_by_odd, [erlang:whereis(?NODE1)]},
|
||||||
{ok, _} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, _, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
{ok, 2} = gen_statem:call(?NODE2, {initiate, {M, F, A}}),
|
{ok, 2} = gen_statem:call(?NODE2, {initiate, {M, F, A}}),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
@ -127,21 +127,21 @@ t_commit_ok_apply_fail_on_other_node_then_recover(_Config) ->
|
||||||
{atomic, []} = emqx_cluster_rpc:status(),
|
{atomic, []} = emqx_cluster_rpc:status(),
|
||||||
Now = erlang:system_time(second),
|
Now = erlang:system_time(second),
|
||||||
{M, F, A} = {?MODULE, failed_on_other_recover_after_5_second, [erlang:whereis(?NODE1), Now]},
|
{M, F, A} = {?MODULE, failed_on_other_recover_after_5_second, [erlang:whereis(?NODE1), Now]},
|
||||||
{ok, _} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, _, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
{ok, _} = emqx_cluster_rpc:multicall(io, format, ["test"]),
|
{ok, _, ok} = emqx_cluster_rpc:multicall(io, format, ["test"]),
|
||||||
{atomic, [Status|L]} = emqx_cluster_rpc:status(),
|
{atomic, [Status|L]} = emqx_cluster_rpc:status(),
|
||||||
?assertEqual([], L),
|
?assertEqual([], L),
|
||||||
?assertEqual({io, format, ["test"]}, maps:get(mfa, Status)),
|
?assertEqual({io, format, ["test"]}, maps:get(mfa, Status)),
|
||||||
?assertEqual(node(), maps:get(node, Status)),
|
?assertEqual(node(), maps:get(node, Status)),
|
||||||
sleep(4000),
|
sleep(3000),
|
||||||
{atomic, [Status1]} = emqx_cluster_rpc:status(),
|
{atomic, [Status1]} = emqx_cluster_rpc:status(),
|
||||||
?assertEqual(Status, Status1),
|
?assertEqual(Status, Status1),
|
||||||
sleep(1600),
|
sleep(2600),
|
||||||
{atomic, NewStatus} = emqx_cluster_rpc:status(),
|
{atomic, NewStatus} = emqx_cluster_rpc:status(),
|
||||||
?assertEqual(3, length(NewStatus)),
|
?assertEqual(3, length(NewStatus)),
|
||||||
Pid = self(),
|
Pid = self(),
|
||||||
MFAEcho = {M1, F1, A1} = {?MODULE, echo, [Pid, test]},
|
MFAEcho = {M1, F1, A1} = {?MODULE, echo, [Pid, test]},
|
||||||
{ok, TnxId} = emqx_cluster_rpc:multicall(M1, F1, A1),
|
{ok, TnxId, ok} = emqx_cluster_rpc:multicall(M1, F1, A1),
|
||||||
{atomic, Query} = emqx_cluster_rpc:query(TnxId),
|
{atomic, Query} = emqx_cluster_rpc:query(TnxId),
|
||||||
?assertEqual(MFAEcho, maps:get(mfa, Query)),
|
?assertEqual(MFAEcho, maps:get(mfa, Query)),
|
||||||
?assertEqual(node(), maps:get(initiator, Query)),
|
?assertEqual(node(), maps:get(initiator, Query)),
|
||||||
|
@ -157,12 +157,12 @@ t_del_stale_mfa(_Config) ->
|
||||||
Keys2 = lists:seq(51, 150),
|
Keys2 = lists:seq(51, 150),
|
||||||
Ids =
|
Ids =
|
||||||
[begin
|
[begin
|
||||||
{ok, TnxId} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, TnxId, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
TnxId end || _ <- Keys],
|
TnxId end || _ <- Keys],
|
||||||
?assertEqual(Keys, Ids),
|
?assertEqual(Keys, Ids),
|
||||||
Ids2 =
|
Ids2 =
|
||||||
[begin
|
[begin
|
||||||
{ok, TnxId} = emqx_cluster_rpc:multicall(M, F, A),
|
{ok, TnxId, ok} = emqx_cluster_rpc:multicall(M, F, A),
|
||||||
TnxId end || _ <- Keys2],
|
TnxId end || _ <- Keys2],
|
||||||
?assertEqual(Keys2, Ids2),
|
?assertEqual(Keys2, Ids2),
|
||||||
sleep(1200),
|
sleep(1200),
|
||||||
|
|
|
@ -13,32 +13,6 @@
|
||||||
%% See the License for the specific language governing permissions and
|
%% See the License for the specific language governing permissions and
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-define(CLUSTER_CALL(Func, Args), ?CLUSTER_CALL(Func, Args, ok)).
|
|
||||||
|
|
||||||
-define(CLUSTER_CALL(Func, Args, ResParttern),
|
|
||||||
%% ekka_mnesia:running_nodes()
|
|
||||||
fun() ->
|
|
||||||
case LocalResult = erlang:apply(?MODULE, Func, Args) of
|
|
||||||
ResParttern ->
|
|
||||||
case rpc:multicall(nodes(), ?MODULE, Func, Args, 5000) of
|
|
||||||
{ResL, []} ->
|
|
||||||
Filter = fun
|
|
||||||
(ResParttern) -> false;
|
|
||||||
({badrpc, {'EXIT', {undef, [{?MODULE, Func0, _, []}]}}})
|
|
||||||
when Func0 =:= Func -> false;
|
|
||||||
(_) -> true
|
|
||||||
end,
|
|
||||||
case lists:filter(Filter, ResL) of
|
|
||||||
[] -> LocalResult;
|
|
||||||
ErrL -> {error, ErrL}
|
|
||||||
end;
|
|
||||||
{ResL, BadNodes} ->
|
|
||||||
{error, {failed_on_nodes, BadNodes, ResL}}
|
|
||||||
end;
|
|
||||||
ErrorResult ->
|
|
||||||
{error, ErrorResult}
|
|
||||||
end
|
|
||||||
end()).
|
|
||||||
|
|
||||||
-define(SAFE_CALL(_EXP_),
|
-define(SAFE_CALL(_EXP_),
|
||||||
?SAFE_CALL(_EXP_, _ = do_nothing)).
|
?SAFE_CALL(_EXP_, _ = do_nothing)).
|
||||||
|
@ -50,4 +24,4 @@
|
||||||
_EXP_ON_FAIL_,
|
_EXP_ON_FAIL_,
|
||||||
{error, {_EXCLASS_, _EXCPTION_, _ST_}}
|
{error, {_EXCLASS_, _EXCPTION_, _ST_}}
|
||||||
end
|
end
|
||||||
end()).
|
end()).
|
||||||
|
|
|
@ -157,7 +157,7 @@ query_failed({_, {OnFailed, Args}}) ->
|
||||||
-spec create(instance_id(), resource_type(), resource_config()) ->
|
-spec create(instance_id(), resource_type(), resource_config()) ->
|
||||||
{ok, resource_data()} | {error, Reason :: term()}.
|
{ok, resource_data()} | {error, Reason :: term()}.
|
||||||
create(InstId, ResourceType, Config) ->
|
create(InstId, ResourceType, Config) ->
|
||||||
?CLUSTER_CALL(create_local, [InstId, ResourceType, Config], {ok, _}).
|
cluster_call(create_local, [InstId, ResourceType, Config]).
|
||||||
|
|
||||||
-spec create_local(instance_id(), resource_type(), resource_config()) ->
|
-spec create_local(instance_id(), resource_type(), resource_config()) ->
|
||||||
{ok, resource_data()} | {error, Reason :: term()}.
|
{ok, resource_data()} | {error, Reason :: term()}.
|
||||||
|
@ -167,7 +167,7 @@ create_local(InstId, ResourceType, Config) ->
|
||||||
-spec create_dry_run(instance_id(), resource_type(), resource_config()) ->
|
-spec create_dry_run(instance_id(), resource_type(), resource_config()) ->
|
||||||
ok | {error, Reason :: term()}.
|
ok | {error, Reason :: term()}.
|
||||||
create_dry_run(InstId, ResourceType, Config) ->
|
create_dry_run(InstId, ResourceType, Config) ->
|
||||||
?CLUSTER_CALL(create_dry_run_local, [InstId, ResourceType, Config]).
|
cluster_call(create_dry_run_local, [InstId, ResourceType, Config]).
|
||||||
|
|
||||||
-spec create_dry_run_local(instance_id(), resource_type(), resource_config()) ->
|
-spec create_dry_run_local(instance_id(), resource_type(), resource_config()) ->
|
||||||
ok | {error, Reason :: term()}.
|
ok | {error, Reason :: term()}.
|
||||||
|
@ -177,7 +177,7 @@ create_dry_run_local(InstId, ResourceType, Config) ->
|
||||||
-spec update(instance_id(), resource_type(), resource_config(), term()) ->
|
-spec update(instance_id(), resource_type(), resource_config(), term()) ->
|
||||||
{ok, resource_data()} | {error, Reason :: term()}.
|
{ok, resource_data()} | {error, Reason :: term()}.
|
||||||
update(InstId, ResourceType, Config, Params) ->
|
update(InstId, ResourceType, Config, Params) ->
|
||||||
?CLUSTER_CALL(update_local, [InstId, ResourceType, Config, Params], {ok, _}).
|
cluster_call(update_local, [InstId, ResourceType, Config, Params]).
|
||||||
|
|
||||||
-spec update_local(instance_id(), resource_type(), resource_config(), term()) ->
|
-spec update_local(instance_id(), resource_type(), resource_config(), term()) ->
|
||||||
{ok, resource_data()} | {error, Reason :: term()}.
|
{ok, resource_data()} | {error, Reason :: term()}.
|
||||||
|
@ -186,7 +186,7 @@ update_local(InstId, ResourceType, Config, Params) ->
|
||||||
|
|
||||||
-spec remove(instance_id()) -> ok | {error, Reason :: term()}.
|
-spec remove(instance_id()) -> ok | {error, Reason :: term()}.
|
||||||
remove(InstId) ->
|
remove(InstId) ->
|
||||||
?CLUSTER_CALL(remove_local, [InstId]).
|
cluster_call(remove_local, [InstId]).
|
||||||
|
|
||||||
-spec remove_local(instance_id()) -> ok | {error, Reason :: term()}.
|
-spec remove_local(instance_id()) -> ok | {error, Reason :: term()}.
|
||||||
remove_local(InstId) ->
|
remove_local(InstId) ->
|
||||||
|
@ -335,3 +335,9 @@ safe_apply(Func, Args) ->
|
||||||
|
|
||||||
str(S) when is_binary(S) -> binary_to_list(S);
|
str(S) when is_binary(S) -> binary_to_list(S);
|
||||||
str(S) when is_list(S) -> S.
|
str(S) when is_list(S) -> S.
|
||||||
|
|
||||||
|
cluster_call(Func, Args) ->
|
||||||
|
case emqx_cluster_rpc:multicall(?MODULE, Func, Args) of
|
||||||
|
{ok, _TxnId, Result} -> Result;
|
||||||
|
Failed -> Failed
|
||||||
|
end.
|
||||||
|
|
|
@ -162,7 +162,7 @@ do_update(InstId, ResourceType, NewConfig, Params) ->
|
||||||
|
|
||||||
do_create(InstId, ResourceType, Config) ->
|
do_create(InstId, ResourceType, Config) ->
|
||||||
case lookup(InstId) of
|
case lookup(InstId) of
|
||||||
{ok, _} -> {error, already_created};
|
{ok, _} -> {ok, already_created};
|
||||||
_ ->
|
_ ->
|
||||||
case emqx_resource:call_start(InstId, ResourceType, Config) of
|
case emqx_resource:call_start(InstId, ResourceType, Config) of
|
||||||
{ok, ResourceState} ->
|
{ok, ResourceState} ->
|
||||||
|
|
|
@ -443,9 +443,9 @@ create_resource(Context, #{type := DB} = Config) ->
|
||||||
ResourceID,
|
ResourceID,
|
||||||
list_to_existing_atom(io_lib:format("~s_~s", [emqx_connector, DB])),
|
list_to_existing_atom(io_lib:format("~s_~s", [emqx_connector, DB])),
|
||||||
Config) of
|
Config) of
|
||||||
{ok, _} ->
|
{ok, already_created} ->
|
||||||
Context#{resource_id => ResourceID};
|
Context#{resource_id => ResourceID};
|
||||||
{error, already_created} ->
|
{ok, _} ->
|
||||||
Context#{resource_id => ResourceID};
|
Context#{resource_id => ResourceID};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
error({load_config_error, Reason})
|
error({load_config_error, Reason})
|
||||||
|
|
|
@ -155,22 +155,6 @@
|
||||||
end
|
end
|
||||||
end()).
|
end()).
|
||||||
|
|
||||||
-define(CLUSTER_CALL(Func, Args), ?CLUSTER_CALL(Func, Args, ok)).
|
|
||||||
|
|
||||||
-define(CLUSTER_CALL(Func, Args, ResParttern),
|
|
||||||
fun() -> case rpc:multicall(ekka_mnesia:running_nodes(), ?MODULE, Func, Args, 5000) of
|
|
||||||
{ResL, []} ->
|
|
||||||
case lists:filter(fun(ResParttern) -> false; (_) -> true end, ResL) of
|
|
||||||
[] -> ResL;
|
|
||||||
ErrL ->
|
|
||||||
?LOG(error, "cluster_call error found, ResL: ~p", [ResL]),
|
|
||||||
throw({Func, ErrL})
|
|
||||||
end;
|
|
||||||
{ResL, BadNodes} ->
|
|
||||||
?LOG(error, "cluster_call bad nodes found: ~p, ResL: ~p", [BadNodes, ResL]),
|
|
||||||
throw({Func, {failed_on_nodes, BadNodes}})
|
|
||||||
end end()).
|
|
||||||
|
|
||||||
%% Tables
|
%% Tables
|
||||||
-define(RULE_TAB, emqx_rule).
|
-define(RULE_TAB, emqx_rule).
|
||||||
-define(ACTION_TAB, emqx_rule_action).
|
-define(ACTION_TAB, emqx_rule_action).
|
||||||
|
|
|
@ -216,7 +216,7 @@ delete_rule(RuleId) ->
|
||||||
case emqx_rule_registry:get_rule(RuleId) of
|
case emqx_rule_registry:get_rule(RuleId) of
|
||||||
{ok, Rule = #rule{actions = Actions}} ->
|
{ok, Rule = #rule{actions = Actions}} ->
|
||||||
try
|
try
|
||||||
_ = ?CLUSTER_CALL(clear_rule, [Rule]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, clear_rule, [Rule]),
|
||||||
ok = emqx_rule_registry:remove_rule(Rule)
|
ok = emqx_rule_registry:remove_rule(Rule)
|
||||||
catch
|
catch
|
||||||
Error:Reason:ST ->
|
Error:Reason:ST ->
|
||||||
|
@ -242,7 +242,7 @@ create_resource(#{type := Type, config := Config0} = Params) ->
|
||||||
ok = emqx_rule_registry:add_resource(Resource),
|
ok = emqx_rule_registry:add_resource(Resource),
|
||||||
%% Note that we will return OK in case of resource creation failure,
|
%% Note that we will return OK in case of resource creation failure,
|
||||||
%% A timer is started to re-start the resource later.
|
%% A timer is started to re-start the resource later.
|
||||||
catch _ = ?CLUSTER_CALL(init_resource, [M, F, ResId, Config]),
|
catch _ = emqx_rule_utils:cluster_call(?MODULE, init_resource, [M, F, ResId, Config]),
|
||||||
{ok, Resource};
|
{ok, Resource};
|
||||||
not_found ->
|
not_found ->
|
||||||
{error, {resource_type_not_found, Type}}
|
{error, {resource_type_not_found, Type}}
|
||||||
|
@ -280,7 +280,7 @@ do_check_and_update_resource(#{id := Id, type := Type, description := NewDescrip
|
||||||
Config = emqx_rule_validator:validate_params(NewConfig, ParamSpec),
|
Config = emqx_rule_validator:validate_params(NewConfig, ParamSpec),
|
||||||
case test_resource(#{type => Type, config => NewConfig}) of
|
case test_resource(#{type => Type, config => NewConfig}) of
|
||||||
ok ->
|
ok ->
|
||||||
_ = ?CLUSTER_CALL(init_resource, [Module, Create, Id, Config]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, init_resource, [Module, Create, Id, Config]),
|
||||||
emqx_rule_registry:add_resource(#resource{
|
emqx_rule_registry:add_resource(#resource{
|
||||||
id = Id,
|
id = Id,
|
||||||
type = Type,
|
type = Type,
|
||||||
|
@ -319,8 +319,8 @@ test_resource(#{type := Type, config := Config0}) ->
|
||||||
Config = emqx_rule_validator:validate_params(Config0, ParamSpec),
|
Config = emqx_rule_validator:validate_params(Config0, ParamSpec),
|
||||||
ResId = resource_id(),
|
ResId = resource_id(),
|
||||||
try
|
try
|
||||||
_ = ?CLUSTER_CALL(init_resource, [ModC, Create, ResId, Config]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, init_resource, [ModC, Create, ResId, Config]),
|
||||||
_ = ?CLUSTER_CALL(clear_resource, [ModD, Destroy, ResId]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, clear_resource, [ModD, Destroy, ResId]),
|
||||||
ok
|
ok
|
||||||
catch
|
catch
|
||||||
throw:Reason -> {error, Reason}
|
throw:Reason -> {error, Reason}
|
||||||
|
@ -359,7 +359,7 @@ delete_resource(ResId) ->
|
||||||
try
|
try
|
||||||
case emqx_rule_registry:remove_resource(ResId) of
|
case emqx_rule_registry:remove_resource(ResId) of
|
||||||
ok ->
|
ok ->
|
||||||
_ = ?CLUSTER_CALL(clear_resource, [ModD, Destroy, ResId]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, clear_resource, [ModD, Destroy, ResId]),
|
||||||
ok;
|
ok;
|
||||||
{error, _} = R -> R
|
{error, _} = R -> R
|
||||||
end
|
end
|
||||||
|
@ -426,7 +426,7 @@ prepare_action(#{name := Name, args := Args0} = Action, NeedInit) ->
|
||||||
ActionInstId = maps:get(id, Action, action_instance_id(Name)),
|
ActionInstId = maps:get(id, Action, action_instance_id(Name)),
|
||||||
case NeedInit of
|
case NeedInit of
|
||||||
true ->
|
true ->
|
||||||
_ = ?CLUSTER_CALL(init_action, [Mod, Create, ActionInstId,
|
_ = emqx_rule_utils:cluster_call(?MODULE, init_action, [Mod, Create, ActionInstId,
|
||||||
with_resource_params(Args)]),
|
with_resource_params(Args)]),
|
||||||
ok;
|
ok;
|
||||||
false -> ok
|
false -> ok
|
||||||
|
@ -485,7 +485,7 @@ may_update_rule_params(Rule, Params = #{on_action_failed := OnFailed}) ->
|
||||||
may_update_rule_params(Rule = #rule{actions = OldActions}, Params = #{actions := Actions}) ->
|
may_update_rule_params(Rule = #rule{actions = OldActions}, Params = #{actions := Actions}) ->
|
||||||
%% prepare new actions before removing old ones
|
%% prepare new actions before removing old ones
|
||||||
NewActions = prepare_actions(Actions, maps:get(enabled, Params, true)),
|
NewActions = prepare_actions(Actions, maps:get(enabled, Params, true)),
|
||||||
_ = ?CLUSTER_CALL(clear_actions, [OldActions]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, clear_actions, [OldActions]),
|
||||||
may_update_rule_params(Rule#rule{actions = NewActions}, maps:remove(actions, Params));
|
may_update_rule_params(Rule#rule{actions = NewActions}, maps:remove(actions, Params));
|
||||||
may_update_rule_params(Rule, _Params) -> %% ignore all the unsupported params
|
may_update_rule_params(Rule, _Params) -> %% ignore all the unsupported params
|
||||||
Rule.
|
Rule.
|
||||||
|
@ -631,7 +631,7 @@ refresh_actions(Actions, Pred) ->
|
||||||
true ->
|
true ->
|
||||||
{ok, #action{module = Mod, on_create = Create}}
|
{ok, #action{module = Mod, on_create = Create}}
|
||||||
= emqx_rule_registry:find_action(ActName),
|
= emqx_rule_registry:find_action(ActName),
|
||||||
_ = ?CLUSTER_CALL(init_action, [Mod, Create, Id, with_resource_params(Args)]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, init_action, [Mod, Create, Id, with_resource_params(Args)]),
|
||||||
refresh_actions(Fallbacks, Pred);
|
refresh_actions(Fallbacks, Pred);
|
||||||
false -> ok
|
false -> ok
|
||||||
end
|
end
|
||||||
|
|
|
@ -221,7 +221,7 @@ remove_rules(Rules) ->
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
insert_rule(Rule) ->
|
insert_rule(Rule) ->
|
||||||
_ = ?CLUSTER_CALL(load_hooks_for_rule, [Rule]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, load_hooks_for_rule, [Rule]),
|
||||||
mnesia:write(?RULE_TAB, Rule, write).
|
mnesia:write(?RULE_TAB, Rule, write).
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
|
@ -231,7 +231,7 @@ delete_rule(RuleId) when is_binary(RuleId) ->
|
||||||
not_found -> ok
|
not_found -> ok
|
||||||
end;
|
end;
|
||||||
delete_rule(Rule) ->
|
delete_rule(Rule) ->
|
||||||
_ = ?CLUSTER_CALL(unload_hooks_for_rule, [Rule]),
|
_ = emqx_rule_utils:cluster_call(?MODULE, unload_hooks_for_rule, [Rule]),
|
||||||
mnesia:delete_object(?RULE_TAB, Rule, write).
|
mnesia:delete_object(?RULE_TAB, Rule, write).
|
||||||
|
|
||||||
load_hooks_for_rule(#rule{for = Topics}) ->
|
load_hooks_for_rule(#rule{for = Topics}) ->
|
||||||
|
@ -476,10 +476,11 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
|
|
||||||
get_all_records(Tab) ->
|
get_all_records(Tab) ->
|
||||||
%mnesia:dirty_match_object(Tab, mnesia:table_info(Tab, wild_pattern)).
|
%mnesia:dirty_match_object(Tab, mnesia:table_info(Tab, wild_pattern)).
|
||||||
%% Wrapping ets to a r/o transaction to avoid reading inconsistent
|
%% Wrapping ets to a transaction to avoid reading inconsistent
|
||||||
|
%% ( nest cluster_call transaction, no a r/o transaction)
|
||||||
%% data during shard bootstrap
|
%% data during shard bootstrap
|
||||||
{atomic, Ret} =
|
{atomic, Ret} =
|
||||||
ekka_mnesia:ro_transaction(?RULE_ENGINE_SHARD,
|
ekka_mnesia:transaction(?RULE_ENGINE_SHARD,
|
||||||
fun() ->
|
fun() ->
|
||||||
ets:tab2list(Tab)
|
ets:tab2list(Tab)
|
||||||
end),
|
end),
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
, can_topic_match_oneof/2
|
, can_topic_match_oneof/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-export([cluster_call/3]).
|
||||||
|
|
||||||
-compile({no_auto_import,
|
-compile({no_auto_import,
|
||||||
[ float/1
|
[ float/1
|
||||||
]}).
|
]}).
|
||||||
|
@ -356,3 +358,7 @@ can_topic_match_oneof(Topic, Filters) ->
|
||||||
lists:any(fun(Fltr) ->
|
lists:any(fun(Fltr) ->
|
||||||
emqx_topic:match(Topic, Fltr)
|
emqx_topic:match(Topic, Fltr)
|
||||||
end, Filters).
|
end, Filters).
|
||||||
|
|
||||||
|
cluster_call(Module, Func, Args) ->
|
||||||
|
{ok, _TnxId, Result} = emqx_cluster_rpc:multicall(Module, Func, Args),
|
||||||
|
Result.
|
||||||
|
|
|
@ -148,6 +148,7 @@ groups() ->
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
|
application:load(emqx_machine),
|
||||||
ok = ekka_mnesia:start(),
|
ok = ekka_mnesia:start(),
|
||||||
ok = emqx_rule_registry:mnesia(boot),
|
ok = emqx_rule_registry:mnesia(boot),
|
||||||
ok = emqx_ct_helpers:start_apps([emqx_rule_engine], fun set_special_configs/1),
|
ok = emqx_ct_helpers:start_apps([emqx_rule_engine], fun set_special_configs/1),
|
||||||
|
@ -181,6 +182,7 @@ end_per_group(_Groupname, _Config) ->
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
init_per_testcase(t_events, Config) ->
|
init_per_testcase(t_events, Config) ->
|
||||||
|
{ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
|
||||||
ok = emqx_rule_engine:load_providers(),
|
ok = emqx_rule_engine:load_providers(),
|
||||||
init_events_counters(),
|
init_events_counters(),
|
||||||
ok = emqx_rule_registry:register_resource_types([make_simple_resource_type(simple_resource_type)]),
|
ok = emqx_rule_registry:register_resource_types([make_simple_resource_type(simple_resource_type)]),
|
||||||
|
@ -214,6 +216,7 @@ init_per_testcase(Test, Config)
|
||||||
;Test =:= t_sqlselect_multi_actoins_3_1
|
;Test =:= t_sqlselect_multi_actoins_3_1
|
||||||
;Test =:= t_sqlselect_multi_actoins_4
|
;Test =:= t_sqlselect_multi_actoins_4
|
||||||
->
|
->
|
||||||
|
emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
|
||||||
ok = emqx_rule_engine:load_providers(),
|
ok = emqx_rule_engine:load_providers(),
|
||||||
ok = emqx_rule_registry:add_action(
|
ok = emqx_rule_registry:add_action(
|
||||||
#action{name = 'crash_action', app = ?APP,
|
#action{name = 'crash_action', app = ?APP,
|
||||||
|
@ -252,6 +255,7 @@ init_per_testcase(Test, Config)
|
||||||
{connsql, SQL}
|
{connsql, SQL}
|
||||||
| Config];
|
| Config];
|
||||||
init_per_testcase(_TestCase, Config) ->
|
init_per_testcase(_TestCase, Config) ->
|
||||||
|
emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
|
||||||
ok = emqx_rule_registry:register_resource_types(
|
ok = emqx_rule_registry:register_resource_types(
|
||||||
[#resource_type{
|
[#resource_type{
|
||||||
name = built_in,
|
name = built_in,
|
||||||
|
|
|
@ -39,6 +39,7 @@ groups() ->
|
||||||
].
|
].
|
||||||
|
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
|
application:load(emqx_machine),
|
||||||
ok = ekka_mnesia:start(),
|
ok = ekka_mnesia:start(),
|
||||||
ok = emqx_rule_registry:mnesia(boot),
|
ok = emqx_rule_registry:mnesia(boot),
|
||||||
Config.
|
Config.
|
||||||
|
@ -65,6 +66,7 @@ end_per_testcase(_, Config) ->
|
||||||
|
|
||||||
t_restart_resource(_) ->
|
t_restart_resource(_) ->
|
||||||
{ok, _} = emqx_rule_monitor:start_link(),
|
{ok, _} = emqx_rule_monitor:start_link(),
|
||||||
|
emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc,1000),
|
||||||
ok = emqx_rule_registry:register_resource_types(
|
ok = emqx_rule_registry:register_resource_types(
|
||||||
[#resource_type{
|
[#resource_type{
|
||||||
name = test_res_1,
|
name = test_res_1,
|
||||||
|
|
Loading…
Reference in New Issue