From 5c66b6f04dce31cce719cc96dffd05398a6cb479 Mon Sep 17 00:00:00 2001 From: Zhongwen Deng Date: Fri, 6 May 2022 15:54:54 +0800 Subject: [PATCH] feat: generate dashboard's dispatch asynchronously --- apps/emqx/src/emqx_listeners.erl | 8 +++- apps/emqx/test/emqx_common_test_helpers.erl | 13 +++++- apps/emqx_dashboard/src/emqx_dashboard.erl | 8 ++-- .../emqx_dashboard/src/emqx_dashboard_app.erl | 9 ++-- ...config.erl => emqx_dashboard_listener.erl} | 44 ++++++++++++++++--- .../emqx_dashboard/src/emqx_dashboard_sup.erl | 6 +-- 6 files changed, 66 insertions(+), 22 deletions(-) rename apps/emqx_dashboard/src/{emqx_dashboard_config.erl => emqx_dashboard_listener.erl} (80%) diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index d4004cbcf..2807608d1 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -209,7 +209,7 @@ start_listener(Type, ListenerName, #{bind := Bind} = Conf) -> Msg = lists:flatten( io_lib:format( "~ts(~ts) : ~p", - [ListenerId, BindStr, element(1, Reason)] + [ListenerId, BindStr, filter_stacktrace(Reason)] ) ), {error, {failed_to_start, Msg}} @@ -514,7 +514,8 @@ foreach_listeners(Do) -> {ok, #{type := Type, name := Name}} = parse_listener_id(Id), case Do(Type, Name, LConf) of {error, {failed_to_start, _} = Reason} -> error(Reason); - _ -> ok + {error, {already_started, _}} -> ok; + ok -> ok end end, list() @@ -568,3 +569,6 @@ convert_certs(CertsDir, Conf) -> clear_certs(CertsDir, Conf) -> OldSSL = maps:get(<<"ssl">>, Conf, undefined), emqx_tls_lib:delete_ssl_files(CertsDir, undefined, OldSSL). + +filter_stacktrace({Reason, _Stacktrace}) -> Reason; +filter_stacktrace(Reason) -> Reason. diff --git a/apps/emqx/test/emqx_common_test_helpers.erl b/apps/emqx/test/emqx_common_test_helpers.erl index 2169f42ba..386c0ea33 100644 --- a/apps/emqx/test/emqx_common_test_helpers.erl +++ b/apps/emqx/test/emqx_common_test_helpers.erl @@ -193,8 +193,11 @@ start_app(App, Schema, ConfigFile, SpecAppConfig) -> copy_certs(App, RenderedConfigFile), SpecAppConfig(App), case application:ensure_all_started(App) of - {ok, _} -> ok; - {error, Reason} -> error({failed_to_start_app, App, Reason}) + {ok, _} -> + ok = ensure_dashboard_listeners_started(App), + ok; + {error, Reason} -> + error({failed_to_start_app, App, Reason}) end. render_config_file(ConfigFile, Vars0) -> @@ -494,3 +497,9 @@ start_ekka() -> application:set_env(mria, db_backend, mnesia), ekka:start() end. + +ensure_dashboard_listeners_started(emqx_dashboard) -> + ok = gen_server:call(emqx_dashboard_listener, sync), + ok; +ensure_dashboard_listeners_started(_App) -> + ok. diff --git a/apps/emqx_dashboard/src/emqx_dashboard.erl b/apps/emqx_dashboard/src/emqx_dashboard.erl index b76858d4b..6c50ca0c7 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard.erl @@ -22,7 +22,8 @@ start_listeners/0, start_listeners/1, stop_listeners/1, - stop_listeners/0 + stop_listeners/0, + list_listeners/0 ]). -export([ @@ -54,7 +55,6 @@ stop_listeners() -> start_listeners(Listeners) -> {ok, _} = application:ensure_all_started(minirest), - init_i18n(), Authorization = {?MODULE, authorize}, GlobalSpec = #{ openapi => "3.0.0", @@ -101,7 +101,6 @@ start_listeners(Listeners) -> [], listeners(Listeners) ), - clear_i18n(), case Res of [] -> ok; _ -> {error, Res} @@ -164,6 +163,9 @@ listeners(Listeners) -> maps:to_list(Listeners) ). +list_listeners() -> + listeners(listeners()). + ip_port(Opts) -> ip_port(maps:take(bind, Opts), Opts). ip_port(error, Opts) -> {Opts#{port => 18083}, 18083}; diff --git a/apps/emqx_dashboard/src/emqx_dashboard_app.erl b/apps/emqx_dashboard/src/emqx_dashboard_app.erl index 094d1cc67..08bfe1d21 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_app.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_app.erl @@ -26,19 +26,18 @@ -include("emqx_dashboard.hrl"). start(_StartType, _StartArgs) -> - {ok, Sup} = emqx_dashboard_sup:start_link(), ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity), + {ok, Sup} = emqx_dashboard_sup:start_link(), case emqx_dashboard:start_listeners() of ok -> emqx_dashboard_cli:load(), - {ok, _Result} = emqx_dashboard_admin:add_default_user(), - ok = emqx_dashboard_config:add_handler(), + {ok, _} = emqx_dashboard_admin:add_default_user(), {ok, Sup}; {error, Reason} -> {error, Reason} end. stop(_State) -> - ok = emqx_dashboard_config:remove_handler(), + ok = emqx_dashboard:stop_listeners(), emqx_dashboard_cli:unload(), - emqx_dashboard:stop_listeners(). + ok. diff --git a/apps/emqx_dashboard/src/emqx_dashboard_config.erl b/apps/emqx_dashboard/src/emqx_dashboard_listener.erl similarity index 80% rename from apps/emqx_dashboard/src/emqx_dashboard_config.erl rename to apps/emqx_dashboard/src/emqx_dashboard_listener.erl index e6e374d23..ad86b732e 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_config.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_listener.erl @@ -13,7 +13,7 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %%-------------------------------------------------------------------- --module(emqx_dashboard_config). +-module(emqx_dashboard_listener). -include_lib("emqx/include/logger.hrl"). -behaviour(emqx_config_handler). @@ -26,33 +26,63 @@ -export([start_link/0]). --export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-export([ + init/1, + handle_continue/2, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3 +]). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). init([]) -> - {ok, #{}, hibernate}. + erlang:process_flag(trap_exit, true), + ok = add_handler(), + {ok, #{}, {continue, regenerate_dispatch}}. + +handle_continue(regenerate_dispatch, State) -> + regenerate_minirest_dispatch(), + {noreply, State, hibernate}. handle_call(_Request, _From, State) -> - {reply, ok, State}. + {reply, ok, State, hibernate}. handle_cast(_Request, State) -> - {noreply, State}. + {noreply, State, hibernate}. handle_info({update_listeners, OldListeners, NewListeners}, State) -> ok = emqx_dashboard:stop_listeners(OldListeners), ok = emqx_dashboard:start_listeners(NewListeners), - {noreply, State}; + regenerate_minirest_dispatch(), + {noreply, State, hibernate}; handle_info(_Info, State) -> - {noreply, State}. + {noreply, State, hibernate}. terminate(_Reason, _State) -> + ok = remove_handler(), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. +%% generate dispatch is very slow. +regenerate_minirest_dispatch() -> + try + emqx_dashboard:init_i18n(), + lists:foreach( + fun(Listener) -> + minirest:regenerate_dispatch(element(1, Listener)) + end, + emqx_dashboard:list_listeners() + ) + catch + _:_ -> emqx_dashboard:clear_i18n() + end. + add_handler() -> Roots = emqx_dashboard_schema:roots(), ok = emqx_config_handler:add_handler(Roots, ?MODULE), diff --git a/apps/emqx_dashboard/src/emqx_dashboard_sup.erl b/apps/emqx_dashboard/src/emqx_dashboard_sup.erl index 6b9e2adcb..89231fadf 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_sup.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_sup.erl @@ -29,8 +29,8 @@ start_link() -> init([]) -> {ok, - {{one_for_one, 10, 100}, [ + {{one_for_one, 5, 100}, [ + ?CHILD(emqx_dashboard_listener), ?CHILD(emqx_dashboard_token), - ?CHILD(emqx_dashboard_monitor), - ?CHILD(emqx_dashboard_config) + ?CHILD(emqx_dashboard_monitor) ]}}.