|
41 | 41 | query_single_active_consumer/1, |
42 | 42 | query_in_memory_usage/1, |
43 | 43 | query_peek/2, |
| 44 | + query_notify_decorators_info/1, |
44 | 45 | usage/1, |
45 | 46 |
|
46 | 47 | zero/1, |
@@ -241,7 +242,7 @@ apply(Meta, #credit{credit = NewCredit, delivery_count = RemoteDelCnt, |
241 | 242 | {State1, ok, Effects} = |
242 | 243 | checkout(Meta, State0, |
243 | 244 | State0#?MODULE{service_queue = ServiceQueue, |
244 | | - consumers = Cons}, []), |
| 245 | + consumers = Cons}, [], false), |
245 | 246 | Response = {send_credit_reply, messages_ready(State1)}, |
246 | 247 | %% by this point all checkouts for the updated credit value |
247 | 248 | %% should be processed so we can evaluate the drain |
@@ -299,7 +300,8 @@ apply(#{index := Index, |
299 | 300 | Exists = maps:is_key(ConsumerId, Consumers), |
300 | 301 | case messages_ready(State0) of |
301 | 302 | 0 -> |
302 | | - update_smallest_raft_index(Index, {dequeue, empty}, State0, []); |
| 303 | + update_smallest_raft_index(Index, {dequeue, empty}, State0, |
| 304 | + [notify_decorators_effect(State0)]); |
303 | 305 | _ when Exists -> |
304 | 306 | %% a dequeue using the same consumer_id isn't possible at this point |
305 | 307 | {State0, {dequeue, empty}}; |
@@ -330,8 +332,8 @@ apply(#{index := Index, |
330 | 332 | {{dequeue, {MsgId, Msg}, Ready-1}, Effects1} |
331 | 333 |
|
332 | 334 | end, |
333 | | - |
334 | | - case evaluate_limit(Index, false, State0, State4, Effects2) of |
| 335 | + NotifyEffect = notify_decorators_effect(State4), |
| 336 | + case evaluate_limit(Index, false, State0, State4, [NotifyEffect | Effects2]) of |
335 | 337 | {State, true, Effects} -> |
336 | 338 | update_smallest_raft_index(Index, Reply, State, Effects); |
337 | 339 | {State, false, Effects} -> |
@@ -456,6 +458,7 @@ apply(#{system_time := Ts} = Meta, {down, Pid, noconnection}, |
456 | 458 | % Monitor the node so that we can "unsuspect" these processes when the node |
457 | 459 | % comes back, then re-issue all monitors and discover the final fate of |
458 | 460 | % these processes |
| 461 | + |
459 | 462 | Effects = case maps:size(State#?MODULE.consumers) of |
460 | 463 | 0 -> |
461 | 464 | [{aux, inactive}, {monitor, node, Node}]; |
@@ -959,6 +962,21 @@ query_peek(Pos, State0) when Pos > 0 -> |
959 | 962 | query_peek(Pos-1, State) |
960 | 963 | end. |
961 | 964 |
|
| 965 | +query_notify_decorators_info(#?MODULE{consumers = Consumers} = State) -> |
| 966 | + MaxActivePriority = maps:fold(fun(_, #consumer{credit = C, |
| 967 | + status = up, |
| 968 | + priority = P0}, MaxP) when C > 0 -> |
| 969 | + P = -P0, |
| 970 | + case MaxP of |
| 971 | + empty -> P; |
| 972 | + MaxP when MaxP > P -> MaxP; |
| 973 | + _ -> P |
| 974 | + end; |
| 975 | + (_, _, MaxP) -> |
| 976 | + MaxP |
| 977 | + end, empty, Consumers), |
| 978 | + IsEmpty = (messages_ready(State) == 0), |
| 979 | + {MaxActivePriority, IsEmpty}. |
962 | 980 |
|
963 | 981 | -spec usage(atom()) -> float(). |
964 | 982 | usage(Name) when is_atom(Name) -> |
@@ -1065,11 +1083,13 @@ cancel_consumer0(Meta, ConsumerId, |
1065 | 1083 | #{ConsumerId := Consumer} -> |
1066 | 1084 | {S, Effects2} = maybe_return_all(Meta, ConsumerId, Consumer, |
1067 | 1085 | S0, Effects0, Reason), |
| 1086 | + |
1068 | 1087 | %% The effects are emitted before the consumer is actually removed |
1069 | 1088 | %% if the consumer has unacked messages. This is a bit weird but |
1070 | 1089 | %% in line with what classic queues do (from an external point of |
1071 | 1090 | %% view) |
1072 | 1091 | Effects = cancel_consumer_effects(ConsumerId, S, Effects2), |
| 1092 | + |
1073 | 1093 | case maps:size(S#?MODULE.consumers) of |
1074 | 1094 | 0 -> |
1075 | 1095 | {S, [{aux, inactive} | Effects]}; |
@@ -1132,7 +1152,7 @@ apply_enqueue(#{index := RaftIdx} = Meta, From, Seq, RawMsg, State0) -> |
1132 | 1152 | case maybe_enqueue(RaftIdx, From, Seq, RawMsg, [], State0) of |
1133 | 1153 | {ok, State1, Effects1} -> |
1134 | 1154 | State2 = append_to_master_index(RaftIdx, State1), |
1135 | | - {State, ok, Effects} = checkout(Meta, State0, State2, Effects1), |
| 1155 | + {State, ok, Effects} = checkout(Meta, State0, State2, Effects1, false), |
1136 | 1156 | {maybe_store_dehydrated_state(RaftIdx, State), ok, Effects}; |
1137 | 1157 | {duplicate, State, Effects} -> |
1138 | 1158 | {State, ok, Effects} |
@@ -1290,7 +1310,7 @@ return(#{index := IncomingRaftIdx} = Meta, ConsumerId, Returned, |
1290 | 1310 | _ -> |
1291 | 1311 | State1 |
1292 | 1312 | end, |
1293 | | - {State, ok, Effects} = checkout(Meta, State0, State2, Effects1), |
| 1313 | + {State, ok, Effects} = checkout(Meta, State0, State2, Effects1, false), |
1294 | 1314 | update_smallest_raft_index(IncomingRaftIdx, State, Effects). |
1295 | 1315 |
|
1296 | 1316 | % used to processes messages that are finished |
@@ -1334,7 +1354,7 @@ complete_and_checkout(#{index := IncomingRaftIdx} = Meta, MsgIds, ConsumerId, |
1334 | 1354 | Discarded = maps:with(MsgIds, Checked0), |
1335 | 1355 | {State2, Effects1} = complete(Meta, ConsumerId, Discarded, Con0, |
1336 | 1356 | Effects0, State0), |
1337 | | - {State, ok, Effects} = checkout(Meta, State0, State2, Effects1), |
| 1357 | + {State, ok, Effects} = checkout(Meta, State0, State2, Effects1, false), |
1338 | 1358 | update_smallest_raft_index(IncomingRaftIdx, State, Effects). |
1339 | 1359 |
|
1340 | 1360 | dead_letter_effects(_Reason, _Discarded, |
@@ -1366,9 +1386,10 @@ dead_letter_effects(Reason, Discarded, |
1366 | 1386 | end} | Effects]. |
1367 | 1387 |
|
1368 | 1388 | cancel_consumer_effects(ConsumerId, |
1369 | | - #?MODULE{cfg = #cfg{resource = QName}}, Effects) -> |
| 1389 | + #?MODULE{cfg = #cfg{resource = QName}} = State, Effects) -> |
1370 | 1390 | [{mod_call, rabbit_quorum_queue, |
1371 | | - cancel_consumer_handler, [QName, ConsumerId]} | Effects]. |
| 1391 | + cancel_consumer_handler, [QName, ConsumerId]}, |
| 1392 | + notify_decorators_effect(State) | Effects]. |
1372 | 1393 |
|
1373 | 1394 | update_smallest_raft_index(Idx, State, Effects) -> |
1374 | 1395 | update_smallest_raft_index(Idx, ok, State, Effects). |
@@ -1503,14 +1524,30 @@ return_all(Meta, #?MODULE{consumers = Cons} = State0, Effects0, ConsumerId, |
1503 | 1524 | end, {State, Effects0}, Checked). |
1504 | 1525 |
|
1505 | 1526 | %% checkout new messages to consumers |
1506 | | -checkout(#{index := Index} = Meta, OldState, State0, Effects0) -> |
| 1527 | +checkout(Meta, OldState, State, Effects) -> |
| 1528 | + checkout(Meta, OldState, State, Effects, true). |
| 1529 | + |
| 1530 | +checkout(#{index := Index} = Meta, #?MODULE{cfg = #cfg{resource = QName}} = OldState, State0, |
| 1531 | + Effects0, HandleConsumerChanges) -> |
1507 | 1532 | {State1, _Result, Effects1} = checkout0(Meta, checkout_one(Meta, State0), |
1508 | 1533 | Effects0, {#{}, #{}}), |
1509 | 1534 | case evaluate_limit(Index, false, OldState, State1, Effects1) of |
1510 | 1535 | {State, true, Effects} -> |
1511 | | - update_smallest_raft_index(Index, State, Effects); |
| 1536 | + case maybe_notify_decorators(State, HandleConsumerChanges) of |
| 1537 | + {true, {MaxActivePriority, IsEmpty}} -> |
| 1538 | + NotifyEffect = notify_decorators_effect(QName, MaxActivePriority, IsEmpty), |
| 1539 | + update_smallest_raft_index(Index, State, [NotifyEffect | Effects]); |
| 1540 | + false -> |
| 1541 | + update_smallest_raft_index(Index, State, Effects) |
| 1542 | + end; |
1512 | 1543 | {State, false, Effects} -> |
1513 | | - {State, ok, Effects} |
| 1544 | + case maybe_notify_decorators(State, HandleConsumerChanges) of |
| 1545 | + {true, {MaxActivePriority, IsEmpty}} -> |
| 1546 | + NotifyEffect = notify_decorators_effect(QName, MaxActivePriority, IsEmpty), |
| 1547 | + {State, ok, [NotifyEffect | Effects]}; |
| 1548 | + false -> |
| 1549 | + {State, ok, Effects} |
| 1550 | + end |
1514 | 1551 | end. |
1515 | 1552 |
|
1516 | 1553 | checkout0(Meta, {success, ConsumerId, MsgId, {RaftIdx, {Header, 'empty'}}, State}, |
@@ -2129,3 +2166,16 @@ get_priority_from_args(#{args := Args}) -> |
2129 | 2166 | end; |
2130 | 2167 | get_priority_from_args(_) -> |
2131 | 2168 | 0. |
| 2169 | + |
| 2170 | +maybe_notify_decorators(_, false) -> |
| 2171 | + false; |
| 2172 | +maybe_notify_decorators(State, _) -> |
| 2173 | + {true, query_notify_decorators_info(State)}. |
| 2174 | + |
| 2175 | +notify_decorators_effect(#?MODULE{cfg = #cfg{resource = QName}} = State) -> |
| 2176 | + {MaxActivePriority, IsEmpty} = query_notify_decorators_info(State), |
| 2177 | + notify_decorators_effect(QName, MaxActivePriority, IsEmpty). |
| 2178 | + |
| 2179 | +notify_decorators_effect(QName, MaxActivePriority, IsEmpty) -> |
| 2180 | + {mod_call, rabbit_quorum_queue, spawn_notify_decorators, |
| 2181 | + [QName, consumer_state_changed, [MaxActivePriority, IsEmpty]]}. |
0 commit comments