Handle old child id format in federation_exchange_link_sup_sup

After an upgrade (multi-node cluster with rolling restart) from pre
3.13.0 with already existing federation links, old child ids are
preserved in the mirrored supervisor.

(cherry picked from commit 311cc925e3)
This commit is contained in:
Péter Gömöri 2023-12-20 00:56:01 +01:00 committed by Michael Klishin
parent d57a31068d
commit 6f79af05f6
1 changed files with 88 additions and 27 deletions

View File

@ -66,42 +66,98 @@ start_link() ->
%% Note that the next supervisor down, rabbit_federation_link_sup, is common
%% between exchanges and queues.
start_child(X) ->
case mirrored_supervisor:start_child(
?SUPERVISOR,
{id(X), {rabbit_federation_link_sup, start_link, [X]},
transient, ?SUPERVISOR_WAIT, supervisor,
[rabbit_federation_link_sup]}) of
{ok, _Pid} -> ok;
{error, {already_started, _Pid}} ->
#exchange{name = ExchangeName} = X,
rabbit_log_federation:debug("Federation link for exchange ~tp was already started",
[rabbit_misc:rs(ExchangeName)]),
ok;
%% A link returned {stop, gone}, the link_sup shut down, that's OK.
{error, {shutdown, _}} -> ok
Result =
case child_exists(X) orelse
mirrored_supervisor:start_child(
?SUPERVISOR,
{id(X), {rabbit_federation_link_sup, start_link, [X]},
transient, ?SUPERVISOR_WAIT, supervisor,
[rabbit_federation_link_sup]}) of
true ->
already_started;
{ok, _Pid} ->
ok;
{error, {already_started, _Pid}} ->
already_started;
%% A link returned {stop, gone}, the link_sup shut down, that's OK.
{error, {shutdown, _}} ->
ok
end,
case Result of
ok ->
ok;
already_started ->
#exchange{name = ExchangeName} = X,
rabbit_log_federation:debug("Federation link for exchange ~tp was already started",
[rabbit_misc:rs(ExchangeName)]),
ok
end.
child_exists(Name) ->
Id = id(Name),
%% older format, pre 3.13.0
OldId = old_id(Name),
lists:any(fun ({ChildId, _, _, _}) ->
ChildId =:= Id orelse ChildId =:= OldId
end,
mirrored_supervisor:which_children(?SUPERVISOR)).
adjust({clear_upstream, VHost, UpstreamName}) ->
_ = [rabbit_federation_link_sup:adjust(Pid, X, {clear_upstream, UpstreamName}) ||
{{_, #exchange{name = Name} = X}, Pid, _, _} <- mirrored_supervisor:which_children(?SUPERVISOR),
Name#resource.virtual_host == VHost],
{Id, Pid, _, _} <- mirrored_supervisor:which_children(?SUPERVISOR),
case Id of
{_, #exchange{name = Name} = X} ->
Name#resource.virtual_host == VHost;
#exchange{name = Name} = X ->
%% Old child id format, pre 3.13.0
Name#resource.virtual_host == VHost
end
],
ok;
adjust(Reason) ->
_ = [rabbit_federation_link_sup:adjust(Pid, X, Reason) ||
{{_, X}, Pid, _, _} <- mirrored_supervisor:which_children(?SUPERVISOR)],
_ = [case Id of
{_, #exchange{} = X} ->
rabbit_federation_link_sup:adjust(Pid, X, Reason);
#exchange{} = X ->
%% Old child id format, pre 3.13.0
rabbit_federation_link_sup:adjust(Pid, X, Reason)
end
|| {Id, Pid, _, _} <- mirrored_supervisor:which_children(?SUPERVISOR)],
ok.
stop_child(X) ->
case mirrored_supervisor:terminate_child(?SUPERVISOR, id(X)) of
ok -> ok;
{error, Err} ->
#exchange{name = ExchangeName} = X,
rabbit_log_federation:warning(
"Attempt to stop a federation link for exchange ~tp failed: ~tp",
[rabbit_misc:rs(ExchangeName), Err]),
ok
end,
ok = mirrored_supervisor:delete_child(?SUPERVISOR, id(X)).
Result =
case stop_and_delete_child(id(X)) of
ok -> ok;
{error, not_found} = Error ->
case rabbit_khepri:is_enabled() of
true ->
%% Old id format is not supported by and cannot exist in Khepri
Error;
false ->
%% try old format, pre 3.13.0
stop_and_delete_child(old_id(X))
end
end,
case Result of
ok ->
ok;
{error, Err} ->
#exchange{name = ExchangeName} = X,
rabbit_log_federation:warning(
"Attempt to stop a federation link for exchange ~tp failed: ~tp",
[rabbit_misc:rs(ExchangeName), Err]),
ok
end.
stop_and_delete_child(Id) ->
case mirrored_supervisor:terminate_child(?SUPERVISOR, Id) of
ok ->
ok = mirrored_supervisor:delete_child(?SUPERVISOR, Id);
{error, not_found} = Error ->
Error
end.
%%----------------------------------------------------------------------------
@ -115,3 +171,8 @@ id(X = #exchange{policy = Policy}) ->
simple_id(#exchange{name = #resource{virtual_host = VHost, name = Name}}) ->
[exchange, VHost, Name].
%% Old child id format, pre 3.13.0
old_id(X = #exchange{policy = Policy}) ->
X1 = rabbit_exchange:immutable(X),
X1#exchange{policy = Policy}.