feat: generate dashboard's dispatch asynchronously

This commit is contained in:
Zhongwen Deng 2022-05-06 15:54:54 +08:00
parent 841acb7828
commit 5c66b6f04d
6 changed files with 66 additions and 22 deletions

View File

@ -209,7 +209,7 @@ start_listener(Type, ListenerName, #{bind := Bind} = Conf) ->
Msg = lists:flatten( Msg = lists:flatten(
io_lib:format( io_lib:format(
"~ts(~ts) : ~p", "~ts(~ts) : ~p",
[ListenerId, BindStr, element(1, Reason)] [ListenerId, BindStr, filter_stacktrace(Reason)]
) )
), ),
{error, {failed_to_start, Msg}} {error, {failed_to_start, Msg}}
@ -514,7 +514,8 @@ foreach_listeners(Do) ->
{ok, #{type := Type, name := Name}} = parse_listener_id(Id), {ok, #{type := Type, name := Name}} = parse_listener_id(Id),
case Do(Type, Name, LConf) of case Do(Type, Name, LConf) of
{error, {failed_to_start, _} = Reason} -> error(Reason); {error, {failed_to_start, _} = Reason} -> error(Reason);
_ -> ok {error, {already_started, _}} -> ok;
ok -> ok
end end
end, end,
list() list()
@ -568,3 +569,6 @@ convert_certs(CertsDir, Conf) ->
clear_certs(CertsDir, Conf) -> clear_certs(CertsDir, Conf) ->
OldSSL = maps:get(<<"ssl">>, Conf, undefined), OldSSL = maps:get(<<"ssl">>, Conf, undefined),
emqx_tls_lib:delete_ssl_files(CertsDir, undefined, OldSSL). emqx_tls_lib:delete_ssl_files(CertsDir, undefined, OldSSL).
filter_stacktrace({Reason, _Stacktrace}) -> Reason;
filter_stacktrace(Reason) -> Reason.

View File

@ -193,8 +193,11 @@ start_app(App, Schema, ConfigFile, SpecAppConfig) ->
copy_certs(App, RenderedConfigFile), copy_certs(App, RenderedConfigFile),
SpecAppConfig(App), SpecAppConfig(App),
case application:ensure_all_started(App) of case application:ensure_all_started(App) of
{ok, _} -> ok; {ok, _} ->
{error, Reason} -> error({failed_to_start_app, App, Reason}) ok = ensure_dashboard_listeners_started(App),
ok;
{error, Reason} ->
error({failed_to_start_app, App, Reason})
end. end.
render_config_file(ConfigFile, Vars0) -> render_config_file(ConfigFile, Vars0) ->
@ -494,3 +497,9 @@ start_ekka() ->
application:set_env(mria, db_backend, mnesia), application:set_env(mria, db_backend, mnesia),
ekka:start() ekka:start()
end. end.
ensure_dashboard_listeners_started(emqx_dashboard) ->
ok = gen_server:call(emqx_dashboard_listener, sync),
ok;
ensure_dashboard_listeners_started(_App) ->
ok.

View File

@ -22,7 +22,8 @@
start_listeners/0, start_listeners/0,
start_listeners/1, start_listeners/1,
stop_listeners/1, stop_listeners/1,
stop_listeners/0 stop_listeners/0,
list_listeners/0
]). ]).
-export([ -export([
@ -54,7 +55,6 @@ stop_listeners() ->
start_listeners(Listeners) -> start_listeners(Listeners) ->
{ok, _} = application:ensure_all_started(minirest), {ok, _} = application:ensure_all_started(minirest),
init_i18n(),
Authorization = {?MODULE, authorize}, Authorization = {?MODULE, authorize},
GlobalSpec = #{ GlobalSpec = #{
openapi => "3.0.0", openapi => "3.0.0",
@ -101,7 +101,6 @@ start_listeners(Listeners) ->
[], [],
listeners(Listeners) listeners(Listeners)
), ),
clear_i18n(),
case Res of case Res of
[] -> ok; [] -> ok;
_ -> {error, Res} _ -> {error, Res}
@ -164,6 +163,9 @@ listeners(Listeners) ->
maps:to_list(Listeners) maps:to_list(Listeners)
). ).
list_listeners() ->
listeners(listeners()).
ip_port(Opts) -> ip_port(maps:take(bind, Opts), Opts). ip_port(Opts) -> ip_port(maps:take(bind, Opts), Opts).
ip_port(error, Opts) -> {Opts#{port => 18083}, 18083}; ip_port(error, Opts) -> {Opts#{port => 18083}, 18083};

View File

@ -26,19 +26,18 @@
-include("emqx_dashboard.hrl"). -include("emqx_dashboard.hrl").
start(_StartType, _StartArgs) -> start(_StartType, _StartArgs) ->
{ok, Sup} = emqx_dashboard_sup:start_link(),
ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity), ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
{ok, Sup} = emqx_dashboard_sup:start_link(),
case emqx_dashboard:start_listeners() of case emqx_dashboard:start_listeners() of
ok -> ok ->
emqx_dashboard_cli:load(), emqx_dashboard_cli:load(),
{ok, _Result} = emqx_dashboard_admin:add_default_user(), {ok, _} = emqx_dashboard_admin:add_default_user(),
ok = emqx_dashboard_config:add_handler(),
{ok, Sup}; {ok, Sup};
{error, Reason} -> {error, Reason} ->
{error, Reason} {error, Reason}
end. end.
stop(_State) -> stop(_State) ->
ok = emqx_dashboard_config:remove_handler(), ok = emqx_dashboard:stop_listeners(),
emqx_dashboard_cli:unload(), emqx_dashboard_cli:unload(),
emqx_dashboard:stop_listeners(). ok.

View File

@ -13,7 +13,7 @@
%% 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.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-module(emqx_dashboard_config). -module(emqx_dashboard_listener).
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-behaviour(emqx_config_handler). -behaviour(emqx_config_handler).
@ -26,33 +26,63 @@
-export([start_link/0]). -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() -> start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) -> 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) -> handle_call(_Request, _From, State) ->
{reply, ok, State}. {reply, ok, State, hibernate}.
handle_cast(_Request, State) -> handle_cast(_Request, State) ->
{noreply, State}. {noreply, State, hibernate}.
handle_info({update_listeners, OldListeners, NewListeners}, State) -> handle_info({update_listeners, OldListeners, NewListeners}, State) ->
ok = emqx_dashboard:stop_listeners(OldListeners), ok = emqx_dashboard:stop_listeners(OldListeners),
ok = emqx_dashboard:start_listeners(NewListeners), ok = emqx_dashboard:start_listeners(NewListeners),
{noreply, State}; regenerate_minirest_dispatch(),
{noreply, State, hibernate};
handle_info(_Info, State) -> handle_info(_Info, State) ->
{noreply, State}. {noreply, State, hibernate}.
terminate(_Reason, _State) -> terminate(_Reason, _State) ->
ok = remove_handler(),
ok. ok.
code_change(_OldVsn, State, _Extra) -> code_change(_OldVsn, State, _Extra) ->
{ok, State}. {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() -> add_handler() ->
Roots = emqx_dashboard_schema:roots(), Roots = emqx_dashboard_schema:roots(),
ok = emqx_config_handler:add_handler(Roots, ?MODULE), ok = emqx_config_handler:add_handler(Roots, ?MODULE),

View File

@ -29,8 +29,8 @@ start_link() ->
init([]) -> init([]) ->
{ok, {ok,
{{one_for_one, 10, 100}, [ {{one_for_one, 5, 100}, [
?CHILD(emqx_dashboard_listener),
?CHILD(emqx_dashboard_token), ?CHILD(emqx_dashboard_token),
?CHILD(emqx_dashboard_monitor), ?CHILD(emqx_dashboard_monitor)
?CHILD(emqx_dashboard_config)
]}}. ]}}.