diff --git a/apps/emqx/src/emqx_config_handler.erl b/apps/emqx/src/emqx_config_handler.erl index 80c47d09e..3752d67ab 100644 --- a/apps/emqx/src/emqx_config_handler.erl +++ b/apps/emqx/src/emqx_config_handler.erl @@ -277,13 +277,38 @@ check_and_save_configs( OldConf = emqx_config:get_root(ConfKeyPath), case do_post_config_update(ConfKeyPath, Handlers, OldConf, NewConf, AppEnvs, UpdateArgs, #{}) of {ok, Result0} -> - ok = emqx_config:save_configs(AppEnvs, NewConf, NewRawConf, OverrideConf, Opts), - Result1 = return_change_result(ConfKeyPath, UpdateArgs), - {ok, Result1#{post_config_update => Result0}}; - Error -> - Error + post_update_ok( + AppEnvs, + NewConf, + NewRawConf, + OverrideConf, + Opts, + ConfKeyPath, + UpdateArgs, + Result0 + ); + {error, {post_config_update, HandlerName, Reason}} -> + HandlePostFailureFun = + fun() -> + post_update_ok( + AppEnvs, + NewConf, + NewRawConf, + OverrideConf, + Opts, + ConfKeyPath, + UpdateArgs, + #{} + ) + end, + {error, {post_config_update, HandlerName, {Reason, HandlePostFailureFun}}} end. +post_update_ok(AppEnvs, NewConf, NewRawConf, OverrideConf, Opts, ConfKeyPath, UpdateArgs, Result0) -> + ok = emqx_config:save_configs(AppEnvs, NewConf, NewRawConf, OverrideConf, Opts), + Result1 = return_change_result(ConfKeyPath, UpdateArgs), + {ok, Result1#{post_config_update => Result0}}. + do_post_config_update(ConfKeyPath, Handlers, OldConf, NewConf, AppEnvs, UpdateArgs, Result) -> do_post_config_update( ConfKeyPath, diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index c290cc88d..1c21d1d2e 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -492,7 +492,9 @@ pre_config_update([?ROOT_KEY], RawConf, RawConf) -> pre_config_update([?ROOT_KEY], NewConf, _RawConf) -> {ok, convert_certs(NewConf)}. -post_config_update([?ROOT_KEY, Type, Name], {create, _Request}, NewConf, undefined, _AppEnvs) -> +post_config_update([?ROOT_KEY, Type, Name], {create, _Request}, NewConf, OldConf, _AppEnvs) when + OldConf =:= undefined orelse OldConf =:= ?TOMBSTONE_TYPE +-> create_listener(Type, Name, NewConf); post_config_update([?ROOT_KEY, Type, Name], {update, _Request}, NewConf, OldConf, _AppEnvs) -> update_listener(Type, Name, {OldConf, NewConf}); diff --git a/apps/emqx/test/emqx_config_handler_SUITE.erl b/apps/emqx/test/emqx_config_handler_SUITE.erl index d2f2faedb..b13da79f6 100644 --- a/apps/emqx/test/emqx_config_handler_SUITE.erl +++ b/apps/emqx/test/emqx_config_handler_SUITE.erl @@ -317,11 +317,19 @@ wait_for_new_pid() -> Pid end. -callback_error(FailedPath, Update, Error) -> +callback_error(FailedPath, Update, ExpectError) -> Opts = #{rawconf_with_defaults => true}, ok = emqx_config_handler:add_handler(FailedPath, ?MODULE), Old = emqx:get_raw_config(FailedPath, undefined), - ?assertEqual(Error, emqx:update_config(FailedPath, Update, Opts)), + Error = emqx:update_config(FailedPath, Update, Opts), + case ExpectError of + {error, {post_config_update, ?MODULE, post_config_update_error}} -> + ?assertMatch( + {error, {post_config_update, ?MODULE, {post_config_update_error, _}}}, Error + ); + _ -> + ?assertEqual(ExpectError, Error) + end, New = emqx:get_raw_config(FailedPath, undefined), ?assertEqual(Old, New), ok = emqx_config_handler:remove_handler(FailedPath), diff --git a/apps/emqx_conf/src/emqx_cluster_rpc.erl b/apps/emqx_conf/src/emqx_cluster_rpc.erl index 91558630f..9e930e693 100644 --- a/apps/emqx_conf/src/emqx_cluster_rpc.erl +++ b/apps/emqx_conf/src/emqx_cluster_rpc.erl @@ -476,7 +476,23 @@ trans_query(TnxId) -> apply_mfa(TnxId, {M, F, A}, Kind) -> Res = try - erlang:apply(M, F, A) + case erlang:apply(M, F, A) of + {error, {post_config_update, HandlerName, {Reason0, PostFailureFun}}} when + Kind =/= ?APPLY_KIND_INITIATE + -> + ?SLOG(error, #{ + msg => "post_config_update_failed", + handler => HandlerName, + reason => Reason0 + }), + PostFailureFun(); + {error, {post_config_update, HandlerName, {Reason0, _Fun}}} when + Kind =:= ?APPLY_KIND_INITIATE + -> + {error, {post_config_update, HandlerName, Reason0}}; + Result -> + Result + end catch throw:Reason -> {error, #{reason => Reason}}; diff --git a/changes/ce/fix-11056.en.md b/changes/ce/fix-11056.en.md new file mode 100644 index 000000000..7c3164289 --- /dev/null +++ b/changes/ce/fix-11056.en.md @@ -0,0 +1,3 @@ +- Fix the issue where newly created listeners do not start properly at times, + when you delete a system default listener and add a new one named 'default', it will not start correctly. +- Fix the bug where configuration failure on certain nodes can cause dashboard unavailability.