Merge pull request #12325 from qzhuyan/dev/william/quic-lstner-reload-binding
feat(quic): support reload with new binding port
This commit is contained in:
commit
8b05d36121
|
@ -24,7 +24,7 @@ IsQuicSupp = fun() ->
|
||||||
end,
|
end,
|
||||||
|
|
||||||
Bcrypt = {bcrypt, {git, "https://github.com/emqx/erlang-bcrypt.git", {tag, "0.6.0"}}},
|
Bcrypt = {bcrypt, {git, "https://github.com/emqx/erlang-bcrypt.git", {tag, "0.6.0"}}},
|
||||||
Quicer = {quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.311"}}}.
|
Quicer = {quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.312"}}}.
|
||||||
|
|
||||||
Dialyzer = fun(Config) ->
|
Dialyzer = fun(Config) ->
|
||||||
{dialyzer, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config),
|
{dialyzer, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config),
|
||||||
|
|
|
@ -469,26 +469,23 @@ do_update_listener(Type, Name, OldConf, NewConf) when
|
||||||
ok = ranch:set_protocol_options(Id, WsOpts),
|
ok = ranch:set_protocol_options(Id, WsOpts),
|
||||||
%% No-op if the listener was not suspended.
|
%% No-op if the listener was not suspended.
|
||||||
ranch:resume_listener(Id);
|
ranch:resume_listener(Id);
|
||||||
do_update_listener(quic = Type, Name, _OldConf, NewConf) ->
|
do_update_listener(quic = Type, Name, OldConf, NewConf) ->
|
||||||
case quicer:listener(listener_id(Type, Name)) of
|
case quicer:listener(listener_id(Type, Name)) of
|
||||||
{ok, ListenerPid} ->
|
{ok, ListenerPid} ->
|
||||||
case quicer_listener:reload(ListenerPid, to_quicer_listener_opts(NewConf)) of
|
ListenOn = quic_listen_on(maps:get(bind, NewConf)),
|
||||||
|
case quicer_listener:reload(ListenerPid, ListenOn, to_quicer_listener_opts(NewConf)) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
ok;
|
||||||
{error, _} = Error ->
|
Error ->
|
||||||
%% @TODO: prefer: case quicer_listener:reload(ListenerPid, to_quicer_listener_opts(OldConf)) of
|
case
|
||||||
case quicer_listener:unlock(ListenerPid, 3000) of
|
quic_listener_conf_rollback(
|
||||||
|
ListenerPid, to_quicer_listener_opts(OldConf), Error
|
||||||
|
)
|
||||||
|
of
|
||||||
ok ->
|
ok ->
|
||||||
?ELOG("Failed to reload QUIC listener ~p, but Rollback success\n", [
|
|
||||||
Error
|
|
||||||
]),
|
|
||||||
{skip, Error};
|
{skip, Error};
|
||||||
RestoreErr ->
|
E ->
|
||||||
?ELOG(
|
E
|
||||||
"Failed to reload QUIC listener ~p, and Rollback failed as well\n",
|
|
||||||
[Error]
|
|
||||||
),
|
|
||||||
{error, {rollback_fail, RestoreErr}}
|
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
E ->
|
E ->
|
||||||
|
@ -991,7 +988,7 @@ quic_listen_on(Bind) ->
|
||||||
Port
|
Port
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec to_quicer_listener_opts(map()) -> quicer:listener_opts().
|
-spec to_quicer_listener_opts(map()) -> map().
|
||||||
to_quicer_listener_opts(Opts) ->
|
to_quicer_listener_opts(Opts) ->
|
||||||
DefAcceptors = erlang:system_info(schedulers_online) * 8,
|
DefAcceptors = erlang:system_info(schedulers_online) * 8,
|
||||||
SSLOpts = maps:from_list(ssl_opts(Opts)),
|
SSLOpts = maps:from_list(ssl_opts(Opts)),
|
||||||
|
@ -1018,3 +1015,27 @@ to_quicer_listener_opts(Opts) ->
|
||||||
),
|
),
|
||||||
%% @NOTE: Optional options take precedence over required options
|
%% @NOTE: Optional options take precedence over required options
|
||||||
maps:merge(Opts2, optional_quic_listener_opts(Opts)).
|
maps:merge(Opts2, optional_quic_listener_opts(Opts)).
|
||||||
|
|
||||||
|
-spec quic_listener_conf_rollback(
|
||||||
|
pid(),
|
||||||
|
map(),
|
||||||
|
Error :: {error, _, _} | {error, _}
|
||||||
|
) -> ok | {error, any()}.
|
||||||
|
quic_listener_conf_rollback(ListenerPid, #{bind := Bind} = Conf, Error) ->
|
||||||
|
ListenOn = quic_listen_on(Bind),
|
||||||
|
case quicer_listener:reload(ListenerPid, ListenOn, Conf) of
|
||||||
|
ok ->
|
||||||
|
?ELOG(
|
||||||
|
"Failed to reload QUIC listener ~p, but Rollback success\n",
|
||||||
|
[
|
||||||
|
Error
|
||||||
|
]
|
||||||
|
),
|
||||||
|
ok;
|
||||||
|
RestoreErr ->
|
||||||
|
?ELOG(
|
||||||
|
"Failed to reload QUIC listener ~p, and Rollback failed as well\n",
|
||||||
|
[Error]
|
||||||
|
),
|
||||||
|
{error, {rollback_fail, RestoreErr}}
|
||||||
|
end.
|
||||||
|
|
|
@ -444,14 +444,45 @@ t_quic_update_opts(Config) ->
|
||||||
| ClientSSLOpts
|
| ClientSSLOpts
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
%% Change the listener port
|
||||||
|
NewPort = emqx_common_test_helpers:select_free_port(ListenerType),
|
||||||
|
{ok, _} = emqx:update_config(
|
||||||
|
[listeners, ListenerType, updated],
|
||||||
|
{update, #{
|
||||||
|
<<"bind">> => format_bind({Host, NewPort})
|
||||||
|
}}
|
||||||
|
),
|
||||||
|
|
||||||
|
%% Connect to old port fail
|
||||||
|
?assertExceptionOneOf(
|
||||||
|
{exit, _},
|
||||||
|
{error, _},
|
||||||
|
ConnectFun(Host, Port, [
|
||||||
|
{cacertfile, filename:join(PrivDir, "ca-next.pem")},
|
||||||
|
{certfile, filename:join(PrivDir, "client.pem")},
|
||||||
|
{keyfile, filename:join(PrivDir, "client.key")}
|
||||||
|
| ClientSSLOpts
|
||||||
|
])
|
||||||
|
),
|
||||||
|
|
||||||
|
%% Connect to new port successfully.
|
||||||
|
C4 = ConnectFun(Host, NewPort, [
|
||||||
|
{cacertfile, filename:join(PrivDir, "ca-next.pem")},
|
||||||
|
{certfile, filename:join(PrivDir, "client.pem")},
|
||||||
|
{keyfile, filename:join(PrivDir, "client.key")}
|
||||||
|
| ClientSSLOpts
|
||||||
|
]),
|
||||||
|
|
||||||
%% Both pre- and post-update clients should be alive.
|
%% Both pre- and post-update clients should be alive.
|
||||||
?assertEqual(pong, emqtt:ping(C1)),
|
?assertEqual(pong, emqtt:ping(C1)),
|
||||||
?assertEqual(pong, emqtt:ping(C2)),
|
?assertEqual(pong, emqtt:ping(C2)),
|
||||||
?assertEqual(pong, emqtt:ping(C3)),
|
?assertEqual(pong, emqtt:ping(C3)),
|
||||||
|
?assertEqual(pong, emqtt:ping(C4)),
|
||||||
|
|
||||||
ok = emqtt:stop(C1),
|
ok = emqtt:stop(C1),
|
||||||
ok = emqtt:stop(C2),
|
ok = emqtt:stop(C2),
|
||||||
ok = emqtt:stop(C3)
|
ok = emqtt:stop(C3),
|
||||||
|
ok = emqtt:stop(C4)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
t_quic_update_opts_fail(Config) ->
|
t_quic_update_opts_fail(Config) ->
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
QUIC listener supports reload the listener binding without disrupting existing connections.
|
2
mix.exs
2
mix.exs
|
@ -795,7 +795,7 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
defp quicer_dep() do
|
defp quicer_dep() do
|
||||||
if enable_quicer?(),
|
if enable_quicer?(),
|
||||||
# in conflict with emqx and emqtt
|
# in conflict with emqx and emqtt
|
||||||
do: [{:quicer, github: "emqx/quic", tag: "0.0.311", override: true}],
|
do: [{:quicer, github: "emqx/quic", tag: "0.0.312", override: true}],
|
||||||
else: []
|
else: []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ assert_otp() ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
quicer() ->
|
quicer() ->
|
||||||
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.311"}}}.
|
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.312"}}}.
|
||||||
|
|
||||||
jq() ->
|
jq() ->
|
||||||
{jq, {git, "https://github.com/emqx/jq", {tag, "v0.3.12"}}}.
|
{jq, {git, "https://github.com/emqx/jq", {tag, "v0.3.12"}}}.
|
||||||
|
|
Loading…
Reference in New Issue