From a2465519148f165b12b35e0bdc03ac1236da5fdc Mon Sep 17 00:00:00 2001 From: JimMoen Date: Wed, 31 Jul 2024 16:15:51 +0800 Subject: [PATCH 1/2] fix: add a startup timeout limit for the plugin application --- apps/emqx_plugins/src/emqx_plugins.erl | 34 ++++++++++++++++++++------ changes/ce/fix-13552.en.md | 8 ++++++ 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 changes/ce/fix-13552.en.md diff --git a/apps/emqx_plugins/src/emqx_plugins.erl b/apps/emqx_plugins/src/emqx_plugins.erl index 253d1b4ef..b13a28e2d 100644 --- a/apps/emqx_plugins/src/emqx_plugins.erl +++ b/apps/emqx_plugins/src/emqx_plugins.erl @@ -992,19 +992,22 @@ do_load_plugin_app(AppName, Ebin) -> end. start_app(App) -> - case application:ensure_all_started(App) of - {ok, Started} -> + case run_with_timeout(application, ensure_all_started, [App], 10_000) of + {ok, {ok, Started}} -> case Started =/= [] of true -> ?SLOG(debug, #{msg => "started_plugin_apps", apps => Started}); false -> ok - end, - ?SLOG(debug, #{msg => "started_plugin_app", app => App}), - ok; - {error, {ErrApp, Reason}} -> + end; + {ok, {error, Reason}} -> + throw(#{ + msg => "failed_to_start_app", + app => App, + reason => Reason + }); + {error, Reason} -> throw(#{ msg => "failed_to_start_plugin_app", app => App, - err_app => ErrApp, reason => Reason }) end. @@ -1525,3 +1528,20 @@ bin(B) when is_binary(B) -> B. wrap_to_list(Path) -> binary_to_list(iolist_to_binary(Path)). + +run_with_timeout(Module, Function, Args, Timeout) -> + Self = self(), + Fun = fun() -> + Result = apply(Module, Function, Args), + Self ! {self(), Result} + end, + Pid = spawn(Fun), + TimerRef = erlang:send_after(Timeout, self(), {timeout, Pid}), + receive + {Pid, Result} -> + erlang:cancel_timer(TimerRef), + {ok, Result}; + {timeout, Pid} -> + exit(Pid, kill), + {error, timeout} + end. diff --git a/changes/ce/fix-13552.en.md b/changes/ce/fix-13552.en.md new file mode 100644 index 000000000..5af1b4140 --- /dev/null +++ b/changes/ce/fix-13552.en.md @@ -0,0 +1,8 @@ +Add a startup timeout limit for the plug-in application. Currently the timeout is 10 seconds. + +Starting a bad plugin while EMQX is running will result in a thrown runtime error. +When EMQX is closed and restarted, the main starting process may hang due to the the plugin application to start failures. + +Maybe restarting with modified: +- Modifed config file: make the bad plugin enabled. +- Add a plugin with bad plugin config. From c658cfe26997a8026606b2ef85221f9255d2dd6d Mon Sep 17 00:00:00 2001 From: JimMoen Date: Wed, 31 Jul 2024 17:17:13 +0800 Subject: [PATCH 2/2] fix: make static_check happy --- apps/emqx_plugins/src/emqx_plugins.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/emqx_plugins/src/emqx_plugins.erl b/apps/emqx_plugins/src/emqx_plugins.erl index b13a28e2d..005df026b 100644 --- a/apps/emqx_plugins/src/emqx_plugins.erl +++ b/apps/emqx_plugins/src/emqx_plugins.erl @@ -1539,7 +1539,7 @@ run_with_timeout(Module, Function, Args, Timeout) -> TimerRef = erlang:send_after(Timeout, self(), {timeout, Pid}), receive {Pid, Result} -> - erlang:cancel_timer(TimerRef), + _ = erlang:cancel_timer(TimerRef), {ok, Result}; {timeout, Pid} -> exit(Pid, kill),