From c77837a9ea0983b74bb1f261f8b8d929fc7b4f14 Mon Sep 17 00:00:00 2001 From: William Yang Date: Mon, 15 Jan 2024 08:24:33 +0100 Subject: [PATCH] feat(quic): support reload with new binding port --- apps/emqx/rebar.config.script | 2 +- apps/emqx/src/emqx_listeners.erl | 51 ++++++++++++++++++++++---------- changes/feat-12325.en.md | 1 + mix.exs | 2 +- rebar.config.erl | 2 +- 5 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 changes/feat-12325.en.md diff --git a/apps/emqx/rebar.config.script b/apps/emqx/rebar.config.script index 8c107d7e5..5f5ce18ba 100644 --- a/apps/emqx/rebar.config.script +++ b/apps/emqx/rebar.config.script @@ -24,7 +24,7 @@ IsQuicSupp = fun() -> end, 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, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config), diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index 74417f3b7..95815dacd 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -469,26 +469,23 @@ do_update_listener(Type, Name, OldConf, NewConf) when ok = ranch:set_protocol_options(Id, WsOpts), %% No-op if the listener was not suspended. 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 {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; - {error, _} = Error -> - %% @TODO: prefer: case quicer_listener:reload(ListenerPid, to_quicer_listener_opts(OldConf)) of - case quicer_listener:unlock(ListenerPid, 3000) of + Error -> + case + quic_listener_conf_rollback( + ListenerPid, to_quicer_listener_opts(OldConf), Error + ) + of ok -> - ?ELOG("Failed to reload QUIC listener ~p, but Rollback success\n", [ - Error - ]), {skip, Error}; - RestoreErr -> - ?ELOG( - "Failed to reload QUIC listener ~p, and Rollback failed as well\n", - [Error] - ), - {error, {rollback_fail, RestoreErr}} + E -> + E end end; E -> @@ -991,7 +988,7 @@ quic_listen_on(Bind) -> Port end. --spec to_quicer_listener_opts(map()) -> quicer:listener_opts(). +-spec to_quicer_listener_opts(map()) -> map(). to_quicer_listener_opts(Opts) -> DefAcceptors = erlang:system_info(schedulers_online) * 8, SSLOpts = maps:from_list(ssl_opts(Opts)), @@ -1018,3 +1015,27 @@ to_quicer_listener_opts(Opts) -> ), %% @NOTE: Optional options take precedence over required options 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. diff --git a/changes/feat-12325.en.md b/changes/feat-12325.en.md new file mode 100644 index 000000000..cc5c5dd7e --- /dev/null +++ b/changes/feat-12325.en.md @@ -0,0 +1 @@ +QUIC listener supports reload the listener binding without disrupting existing connections. diff --git a/mix.exs b/mix.exs index 5ef6fef36..7389cb0f9 100644 --- a/mix.exs +++ b/mix.exs @@ -795,7 +795,7 @@ defmodule EMQXUmbrella.MixProject do defp quicer_dep() do if enable_quicer?(), # 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: [] end diff --git a/rebar.config.erl b/rebar.config.erl index e77b799f8..e374959dc 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -36,7 +36,7 @@ assert_otp() -> end. 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, {git, "https://github.com/emqx/jq", {tag, "v0.3.12"}}}.