fix(rule_engine): reformat some code for dependent rules discovery

This commit is contained in:
Shawn 2021-04-26 18:10:53 +08:00 committed by turtleDeng
parent 07d5c0f9df
commit 9fd43ef882
3 changed files with 43 additions and 37 deletions

View File

@ -249,40 +249,30 @@ create_resource(#{type := Type, config := Config0} = Params) ->
-spec(update_resource(resource_id(), map()) -> ok | {error, Reason :: term()}). -spec(update_resource(resource_id(), map()) -> ok | {error, Reason :: term()}).
update_resource(ResId, NewParams) -> update_resource(ResId, NewParams) ->
try case emqx_rule_registry:find_enabled_rules_depends_on_resource(ResId) of
lists:foreach(fun(#rule{id = RuleId, enabled = Enabled, actions = Actions}) -> [] -> check_and_update_resource(ResId, NewParams);
lists:foreach( Rules ->
fun (#action_instance{args = #{<<"$resource">> := ResId1}}) {error, {dependent_rules_exists, [Id || #rule{id = Id} <- Rules]}}
when ResId =:= ResId1, Enabled =:= true ->
throw({dependency_exists, RuleId});
(_) -> ok
end, Actions)
end, ets:tab2list(?RULE_TAB)),
do_update_resource_check(ResId, NewParams)
catch _ : Reason ->
{error, Reason}
end. end.
do_update_resource_check(Id, NewParams) -> check_and_update_resource(Id, NewParams) ->
case emqx_rule_registry:find_resource(Id) of case emqx_rule_registry:find_resource(Id) of
{ok, #resource{id = Id, {ok, #resource{id = Id, type = Type, config = OldConfig, description = OldDescr}} ->
type = Type,
config = OldConfig,
description = OldDescription} = _OldResource} ->
try try
Conifg = maps:get(<<"config">>, NewParams, OldConfig), Conifg = maps:get(<<"config">>, NewParams, OldConfig),
Descr = maps:get(<<"description">>, NewParams, OldDescription), Descr = maps:get(<<"description">>, NewParams, OldDescr),
do_update_resource(#{id => Id, config => Conifg, type => Type, do_check_and_update_resource(#{id => Id, config => Conifg, type => Type,
description => Descr}), description => Descr})
ok catch Error:Reason:ST ->
catch _ : Reason -> ?LOG(error, "check_and_update_resource failed: ~0p", [{Error, Reason, ST}]),
{error, Reason} {error, Reason}
end; end;
_Other -> _Other ->
{error, not_found} {error, not_found}
end. end.
do_update_resource(#{id := Id, type := Type, description := NewDescription, config := NewConfig}) -> do_check_and_update_resource(#{id := Id, type := Type, description := NewDescription,
config := NewConfig}) ->
case emqx_rule_registry:find_resource_type(Type) of case emqx_rule_registry:find_resource_type(Type) of
{ok, #resource_type{on_create = {Module, Create}, {ok, #resource_type{on_create = {Module, Create},
params_spec = ParamSpec}} -> params_spec = ParamSpec}} ->
@ -296,7 +286,8 @@ do_update_resource(#{id := Id, type := Type, description := NewDescription, conf
config = Config, config = Config,
description = NewDescription, description = NewDescription,
created_at = erlang:system_time(millisecond) created_at = erlang:system_time(millisecond)
}); }),
ok;
{error, Reason} -> {error, Reason} ->
error({error, Reason}) error({error, Reason})
end end

View File

@ -180,6 +180,7 @@
-define(ERR_NO_ACTION(NAME), list_to_binary(io_lib:format("Action ~s Not Found", [(NAME)]))). -define(ERR_NO_ACTION(NAME), list_to_binary(io_lib:format("Action ~s Not Found", [(NAME)]))).
-define(ERR_NO_RESOURCE(RESID), list_to_binary(io_lib:format("Resource ~s Not Found", [(RESID)]))). -define(ERR_NO_RESOURCE(RESID), list_to_binary(io_lib:format("Resource ~s Not Found", [(RESID)]))).
-define(ERR_NO_RESOURCE_TYPE(TYPE), list_to_binary(io_lib:format("Resource Type ~s Not Found", [(TYPE)]))). -define(ERR_NO_RESOURCE_TYPE(TYPE), list_to_binary(io_lib:format("Resource Type ~s Not Found", [(TYPE)]))).
-define(ERR_DEP_RULES_EXISTS(RULEIDS), list_to_binary(io_lib:format("Found rules ~0p depends on this resource, disable them first", [(RULEIDS)]))).
-define(ERR_BADARGS(REASON), -define(ERR_BADARGS(REASON),
begin begin
R0 = list_to_binary(io_lib:format("~0p", [REASON])), R0 = list_to_binary(io_lib:format("~0p", [REASON])),
@ -342,14 +343,11 @@ update_resource(#{id := Id}, NewParams) ->
ok -> ok ->
return(ok); return(ok);
{error, not_found} -> {error, not_found} ->
?LOG(error, "Resource not found: ~0p", [Id]),
return({error, 400, <<"Resource not found:", Id/binary>>}); return({error, 400, <<"Resource not found:", Id/binary>>});
{error, {init_resource, _}} -> {error, {init_resource, _}} ->
?LOG(error, "Init resource failure: ~0p", [Id]),
return({error, 500, <<"Init resource failure:", Id/binary>>}); return({error, 500, <<"Init resource failure:", Id/binary>>});
{error, {dependency_exists, RuleId}} -> {error, {dependent_rules_exists, RuleIds}} ->
?LOG(error, "Dependency exists: ~0p", [RuleId]), return({error, 400, ?ERR_DEP_RULES_EXISTS(RuleIds)});
return({error, 500, <<"Dependency exists:", RuleId/binary>>});
{error, Reason} -> {error, Reason} ->
?LOG(error, "Resource update failed: ~0p", [Reason]), ?LOG(error, "Resource update failed: ~0p", [Reason]),
return({error, 500, <<"Resource update failed!">>}) return({error, 500, <<"Resource update failed!">>})
@ -359,6 +357,8 @@ delete_resource(#{id := Id}, _Params) ->
case emqx_rule_engine:delete_resource(Id) of case emqx_rule_engine:delete_resource(Id) of
ok -> return(ok); ok -> return(ok);
{error, not_found} -> return(ok); {error, not_found} -> return(ok);
{error, {dependent_rules_exists, RuleIds}} ->
return({error, 400, ?ERR_DEP_RULES_EXISTS(RuleIds)});
{error, Reason} -> {error, Reason} ->
return({error, 400, ?ERR_BADARGS(Reason)}) return({error, 400, ?ERR_BADARGS(Reason)})
end. end.

View File

@ -63,6 +63,8 @@
%% Resource Types %% Resource Types
-export([ get_resource_types/0 -export([ get_resource_types/0
, find_resource_type/1 , find_resource_type/1
, find_rules_depends_on_resource/1
, find_enabled_rules_depends_on_resource/1
, register_resource_types/1 , register_resource_types/1
, unregister_resource_types_of/1 , unregister_resource_types_of/1
]). ]).
@ -368,20 +370,33 @@ remove_resource_params(ResId) ->
%% @private %% @private
delete_resource(ResId) -> delete_resource(ResId) ->
lists:foreach(fun(#rule{id = Id, actions = Actions}) -> case find_enabled_rules_depends_on_resource(ResId) of
lists:foreach( [] -> ok;
fun (#action_instance{args = #{<<"$resource">> := ResId1}}) Rules ->
when ResId =:= ResId1 -> throw({dependent_rules_exists, [Id || #rule{id = Id} <- Rules]})
throw({dependency_exists, {rule, Id}}); end,
(_) -> ok
end, Actions)
end, get_rules()),
mnesia:delete(?RES_TAB, ResId, write). mnesia:delete(?RES_TAB, ResId, write).
%% @private %% @private
insert_resource(Resource) -> insert_resource(Resource) ->
mnesia:write(?RES_TAB, Resource, write). mnesia:write(?RES_TAB, Resource, write).
find_enabled_rules_depends_on_resource(ResId) ->
[R || #rule{enabled = true} = R <- find_rules_depends_on_resource(ResId)].
find_rules_depends_on_resource(ResId) ->
lists:foldl(fun(#rule{actions = Actions} = R, Rules) ->
case search_action_despends_on_resource(ResId, Actions) of
false -> Rules;
{value, _} -> [R | Rules]
end
end, [], get_rules()).
search_action_despends_on_resource(ResId, Actions) ->
lists:search(fun(#action_instance{args = #{<<"$resource">> := ResId0}}) ->
ResId0 =:= ResId
end, Actions).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Resource Type Management %% Resource Type Management
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------