Просмотр исходного кода

feat: generate dashboard's dispatch asynchronously

Zhongwen Deng 3 лет назад
Родитель
Сommit
5c66b6f04d

+ 6 - 2
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.

+ 11 - 2
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.

+ 5 - 3
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};

+ 4 - 5
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.

+ 37 - 7
apps/emqx_dashboard/src/emqx_dashboard_config.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),

+ 3 - 3
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)
         ]}}.