Use ra_leaderboard when initialising quorum queue client.

If available failure the leader in ra_leaderboard over the one
in the queue record as with mnesia the queue record can be
very stale if a node has a network issue that hasn't yet been
detected by the runtime.

Also change some legacy naming in rabbit_fifo_client
This commit is contained in:
Karl Nilsson 2023-08-31 17:11:44 +01:00
parent 0b92354cde
commit 9e18c6c817
2 changed files with 28 additions and 22 deletions

View File

@ -147,10 +147,10 @@ enqueue(QName, Correlation, Msg,
next_seq = Seq,
next_enqueue_seq = EnqueueSeq,
cfg = #cfg{soft_limit = SftLmt}} = State0) ->
Server = pick_server(State0),
ServerId = pick_server(State0),
% by default there is no correlation id
Cmd = rabbit_fifo:make_enqueue(self(), EnqueueSeq, Msg),
ok = ra:pipeline_command(Server, Cmd, Seq, low),
ok = ra:pipeline_command(ServerId, Cmd, Seq, low),
Tag = case map_size(Pending) >= SftLmt of
true -> slow;
false -> ok
@ -199,9 +199,9 @@ enqueue(QName, Msg, State) ->
| {empty, state()} | {error | timeout, term()}.
dequeue(QueueName, ConsumerTag, Settlement,
#state{cfg = #cfg{timeout = Timeout}} = State0) ->
Node = pick_server(State0),
ServerId = pick_server(State0),
ConsumerId = consumer_id(ConsumerTag),
case ra:process_command(Node,
case ra:process_command(ServerId,
rabbit_fifo:make_checkout(ConsumerId,
{dequeue, Settlement},
#{}),
@ -242,9 +242,9 @@ add_delivery_count_header(Msg, Count) ->
-spec settle(rabbit_fifo:consumer_tag(), [rabbit_fifo:msg_id()], state()) ->
{state(), list()}.
settle(ConsumerTag, [_|_] = MsgIds, #state{slow = false} = State0) ->
Node = pick_server(State0),
ServerId = pick_server(State0),
Cmd = rabbit_fifo:make_settle(consumer_id(ConsumerTag), MsgIds),
{send_command(Node, undefined, Cmd, normal, State0), []};
{send_command(ServerId, undefined, Cmd, normal, State0), []};
settle(ConsumerTag, [_|_] = MsgIds,
#state{unsent_commands = Unsent0} = State0) ->
ConsumerId = consumer_id(ConsumerTag),
@ -270,10 +270,10 @@ settle(ConsumerTag, [_|_] = MsgIds,
-spec return(rabbit_fifo:consumer_tag(), [rabbit_fifo:msg_id()], state()) ->
{state(), list()}.
return(ConsumerTag, [_|_] = MsgIds, #state{slow = false} = State0) ->
Node = pick_server(State0),
ServerId = pick_server(State0),
% TODO: make rabbit_fifo return support lists of message ids
Cmd = rabbit_fifo:make_return(consumer_id(ConsumerTag), MsgIds),
{send_command(Node, undefined, Cmd, normal, State0), []};
{send_command(ServerId, undefined, Cmd, normal, State0), []};
return(ConsumerTag, [_|_] = MsgIds,
#state{unsent_commands = Unsent0} = State0) ->
ConsumerId = consumer_id(ConsumerTag),
@ -295,9 +295,9 @@ return(ConsumerTag, [_|_] = MsgIds,
-spec discard(rabbit_fifo:consumer_tag(), [rabbit_fifo:msg_id()], state()) ->
{state(), list()}.
discard(ConsumerTag, [_|_] = MsgIds, #state{slow = false} = State0) ->
Node = pick_server(State0),
ServerId = pick_server(State0),
Cmd = rabbit_fifo:make_discard(consumer_id(ConsumerTag), MsgIds),
{send_command(Node, undefined, Cmd, normal, State0), []};
{send_command(ServerId, undefined, Cmd, normal, State0), []};
discard(ConsumerTag, [_|_] = MsgIds,
#state{unsent_commands = Unsent0} = State0) ->
ConsumerId = consumer_id(ConsumerTag),
@ -404,10 +404,10 @@ credit(ConsumerTag, Credit, Drain,
%% the last received msgid provides us with the delivery count if we
%% add one as it is 0 indexed
C = maps:get(ConsumerTag, CDels, #consumer{last_msg_id = -1}),
Node = pick_server(State0),
ServerId = pick_server(State0),
Cmd = rabbit_fifo:make_credit(ConsumerId, Credit,
C#consumer.last_msg_id + 1, Drain),
{send_command(Node, undefined, Cmd, normal, State0), []}.
{send_command(ServerId, undefined, Cmd, normal, State0), []}.
%% @doc Cancels a checkout with the rabbit_fifo queue for the consumer tag
%%
@ -560,10 +560,10 @@ handle_ra_event(QName, From, {applied, Seqs},
add_command(Cid, discard,
Discards, Acc)))
end, [], State1#state.unsent_commands),
Node = pick_server(State2),
ServerId = pick_server(State2),
%% send all the settlements and returns
State = lists:foldl(fun (C, S0) ->
send_command(Node, undefined, C,
send_command(ServerId, undefined, C,
normal, S0)
end, State2, Commands),
{ok, State, [{unblock, cluster_name(State)} | Actions]};
@ -624,9 +624,9 @@ handle_ra_event(_QName, _Leader, {machine, eol}, State) ->
%% @returns `ok'
-spec untracked_enqueue([ra:server_id()], term()) ->
ok.
untracked_enqueue([Node | _], Msg) ->
untracked_enqueue([ServerId | _], Msg) ->
Cmd = rabbit_fifo:make_enqueue(undefined, undefined, Msg),
ok = ra:pipeline_command(Node, Cmd),
ok = ra:pipeline_command(ServerId, Cmd),
ok.
%% Internal
@ -856,10 +856,10 @@ send_command(Server, Correlation, Command, Priority,
next_seq = Seq + 1,
slow = Tag == slow}.
resend_command(Node, Correlation, Command,
resend_command(ServerId, Correlation, Command,
#state{pending = Pending,
next_seq = Seq} = State) ->
ok = ra:pipeline_command(Node, Command, Seq),
ok = ra:pipeline_command(ServerId, Command, Seq),
State#state{pending = Pending#{Seq => {Correlation, Command}},
next_seq = Seq + 1}.

View File

@ -161,11 +161,17 @@ is_compatible(_, _, _) ->
-spec init(amqqueue:amqqueue()) -> {ok, rabbit_fifo_client:state()}.
init(Q) when ?is_amqqueue(Q) ->
{ok, SoftLimit} = application:get_env(rabbit, quorum_commands_soft_limit),
%% This lookup could potentially return an {error, not_found}, but we do not
%% know what to do if the queue has `disappeared`. Let it crash.
{Name, _LeaderNode} = Leader = amqqueue:get_pid(Q),
{Name, _} = MaybeLeader = amqqueue:get_pid(Q),
Leader = case ra_leaderboard:lookup_leader(Name) of
undefined ->
%% leader from queue record will have to suffice
MaybeLeader;
LikelyLeader ->
LikelyLeader
end,
Nodes = get_nodes(Q),
%% Ensure the leader is listed first
%% Ensure the leader is listed first to increase likelihood of first
%% server tried is the one we want
Servers0 = [{Name, N} || N <- Nodes],
Servers = [Leader | lists:delete(Leader, Servers0)],
{ok, rabbit_fifo_client:init(Servers, SoftLimit)}.