feat(listen): support hot update of WS/WSS options as well
However, currently any transport option changes will cause listener to restart, which slightly impacts the availability of the broker.
This commit is contained in:
parent
68bbbec556
commit
036048b9ab
|
@ -293,18 +293,14 @@ update_listener(Type, Name, Conf = #{enable := true}, #{enable := false}) ->
|
||||||
stop_listener(Type, Name, Conf);
|
stop_listener(Type, Name, Conf);
|
||||||
update_listener(Type, Name, #{enable := false}, Conf = #{enable := true}) ->
|
update_listener(Type, Name, #{enable := false}, Conf = #{enable := true}) ->
|
||||||
start_listener(Type, Name, Conf);
|
start_listener(Type, Name, Conf);
|
||||||
update_listener(Type, Name, OldConf = #{bind := Bind}, NewConf = #{bind := Bind}) ->
|
update_listener(Type, Name, OldConf, NewConf) ->
|
||||||
case do_update_listener(Type, Name, OldConf, NewConf) of
|
case do_update_listener(Type, Name, OldConf, NewConf) of
|
||||||
ok ->
|
ok ->
|
||||||
ok = maybe_unregister_ocsp_stapling_refresh(Type, Name, NewConf),
|
ok = maybe_unregister_ocsp_stapling_refresh(Type, Name, NewConf),
|
||||||
ok;
|
ok;
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
restart_listener(Type, Name, OldConf, NewConf)
|
restart_listener(Type, Name, OldConf, NewConf)
|
||||||
end;
|
end.
|
||||||
update_listener(Type, Name, OldConf, NewConf) ->
|
|
||||||
%% TODO
|
|
||||||
%% Again, we're not strictly required to drop live connections in this case.
|
|
||||||
restart_listener(Type, Name, OldConf, NewConf).
|
|
||||||
|
|
||||||
restart_listener(Type, Name, OldConf, NewConf) ->
|
restart_listener(Type, Name, OldConf, NewConf) ->
|
||||||
case stop_listener(Type, Name, OldConf) of
|
case stop_listener(Type, Name, OldConf) of
|
||||||
|
@ -403,11 +399,11 @@ do_start_listener(Type, Name, #{bind := ListenOn} = Opts) when ?ESOCKD_LISTENER(
|
||||||
merge_default(esockd_opts(Id, Type, Name, Opts))
|
merge_default(esockd_opts(Id, Type, Name, Opts))
|
||||||
);
|
);
|
||||||
%% Start MQTT/WS listener
|
%% Start MQTT/WS listener
|
||||||
do_start_listener(Type, ListenerName, #{bind := ListenOn} = Opts) when ?COWBOY_LISTENER(Type) ->
|
do_start_listener(Type, Name, Opts) when ?COWBOY_LISTENER(Type) ->
|
||||||
Id = listener_id(Type, ListenerName),
|
Id = listener_id(Type, Name),
|
||||||
ok = add_limiter_bucket(Id, limiter(Opts)),
|
ok = add_limiter_bucket(Id, limiter(Opts)),
|
||||||
RanchOpts = ranch_opts(Type, ListenOn, Opts),
|
RanchOpts = ranch_opts(Type, Opts),
|
||||||
WsOpts = ws_opts(Type, ListenerName, Opts),
|
WsOpts = ws_opts(Type, Name, Opts),
|
||||||
case Type of
|
case Type of
|
||||||
ws -> cowboy:start_clear(Id, RanchOpts, WsOpts);
|
ws -> cowboy:start_clear(Id, RanchOpts, WsOpts);
|
||||||
wss -> cowboy:start_tls(Id, RanchOpts, WsOpts)
|
wss -> cowboy:start_tls(Id, RanchOpts, WsOpts)
|
||||||
|
@ -482,10 +478,36 @@ do_start_listener(quic, ListenerName, #{bind := Bind} = Opts) ->
|
||||||
{ok, {skipped, quic_app_missing}}
|
{ok, {skipped, quic_app_missing}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_update_listener(Type, Name, _OldConf, NewConf) when ?ESOCKD_LISTENER(Type) ->
|
do_update_listener(Type, Name, OldConf, NewConf = #{bind := ListenOn}) when
|
||||||
|
?ESOCKD_LISTENER(Type)
|
||||||
|
->
|
||||||
Id = listener_id(Type, Name),
|
Id = listener_id(Type, Name),
|
||||||
ListenOn = maps:get(bind, NewConf),
|
case maps:get(bind, OldConf) of
|
||||||
esockd:set_options({Id, ListenOn}, esockd_opts(Id, Type, Name, NewConf));
|
ListenOn ->
|
||||||
|
esockd:set_options({Id, ListenOn}, esockd_opts(Id, Type, Name, NewConf));
|
||||||
|
_Different ->
|
||||||
|
%% TODO
|
||||||
|
%% Again, we're not strictly required to drop live connections in this case.
|
||||||
|
{error, not_supported}
|
||||||
|
end;
|
||||||
|
do_update_listener(Type, Name, OldConf, NewConf) when
|
||||||
|
?COWBOY_LISTENER(Type)
|
||||||
|
->
|
||||||
|
Id = listener_id(Type, Name),
|
||||||
|
RanchOpts = ranch_opts(Type, NewConf),
|
||||||
|
WsOpts = ws_opts(Type, Name, NewConf),
|
||||||
|
case ranch_opts(Type, OldConf) of
|
||||||
|
RanchOpts ->
|
||||||
|
%% Transport options did not change, no need to touch the listener.
|
||||||
|
ok;
|
||||||
|
_Different ->
|
||||||
|
%% Transport options changed, we need to tear down the listener.
|
||||||
|
ok = ranch:suspend_listener(Id),
|
||||||
|
ok = ranch:set_transport_options(Id, RanchOpts)
|
||||||
|
end,
|
||||||
|
ok = ranch:set_protocol_options(Id, WsOpts),
|
||||||
|
%% No-op if the listener was not suspended.
|
||||||
|
ranch:resume_listener(Id);
|
||||||
do_update_listener(_Type, _Name, _OldConf, _NewConf) ->
|
do_update_listener(_Type, _Name, _OldConf, _NewConf) ->
|
||||||
{error, not_supported}.
|
{error, not_supported}.
|
||||||
|
|
||||||
|
@ -591,19 +613,20 @@ esockd_opts(ListenerId, Type, Name, Opts0) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
ws_opts(Type, ListenerName, Opts) ->
|
ws_opts(Type, ListenerName, Opts) ->
|
||||||
WsPaths = [
|
WsPath = emqx_utils_maps:deep_get([websocket, mqtt_path], Opts, "/mqtt"),
|
||||||
{emqx_utils_maps:deep_get([websocket, mqtt_path], Opts, "/mqtt"), emqx_ws_connection, #{
|
WsRoutes = [
|
||||||
|
{WsPath, emqx_ws_connection, #{
|
||||||
zone => zone(Opts),
|
zone => zone(Opts),
|
||||||
listener => {Type, ListenerName},
|
listener => {Type, ListenerName},
|
||||||
limiter => limiter(Opts),
|
limiter => limiter(Opts),
|
||||||
enable_authn => enable_authn(Opts)
|
enable_authn => enable_authn(Opts)
|
||||||
}}
|
}}
|
||||||
],
|
],
|
||||||
Dispatch = cowboy_router:compile([{'_', WsPaths}]),
|
Dispatch = cowboy_router:compile([{'_', WsRoutes}]),
|
||||||
ProxyProto = maps:get(proxy_protocol, Opts, false),
|
ProxyProto = maps:get(proxy_protocol, Opts, false),
|
||||||
#{env => #{dispatch => Dispatch}, proxy_header => ProxyProto}.
|
#{env => #{dispatch => Dispatch}, proxy_header => ProxyProto}.
|
||||||
|
|
||||||
ranch_opts(Type, ListenOn, Opts) ->
|
ranch_opts(Type, Opts = #{bind := ListenOn}) ->
|
||||||
NumAcceptors = maps:get(acceptors, Opts, 4),
|
NumAcceptors = maps:get(acceptors, Opts, 4),
|
||||||
MaxConnections = maps:get(max_connections, Opts, 1024),
|
MaxConnections = maps:get(max_connections, Opts, 1024),
|
||||||
SocketOpts =
|
SocketOpts =
|
||||||
|
|
Loading…
Reference in New Issue