@@ -696,12 +696,18 @@ calculate_msg_expiry(TTL) -> now_micros() + (TTL * 1000).
696696drop_expired_messages (State = # q {ttl = undefined }) ->
697697 State ;
698698drop_expired_messages (State = # q {backing_queue_state = BQS ,
699- backing_queue = BQ }) ->
699+ backing_queue = BQ }) ->
700700 Now = now_micros (),
701- BQS1 = BQ :dropwhile (
702- fun (# message_properties {expiry = Expiry }) -> Now > Expiry end ,
703- dead_letter_fun (expired , State ),
704- BQS ),
701+ DLXFun = dead_letter_fun (expired , State ),
702+ ExpirePred = fun (# message_properties {expiry = Expiry }) -> Now > Expiry end ,
703+ case DLXFun of
704+ undefined -> {undefined , BQS1 } = BQ :dropwhile (ExpirePred , false , BQS ),
705+ BQS1 ;
706+ _ -> {Msgs , BQS1 } = BQ :dropwhile (ExpirePred , true , BQS ),
707+ lists :foreach (
708+ fun ({Msg , AckTag }) -> DLXFun (Msg , AckTag ) end , Msgs ),
709+ BQS1
710+ end ,
705711 ensure_ttl_timer (State # q {backing_queue_state = BQS1 }).
706712
707713ensure_ttl_timer (State = # q {backing_queue = BQ ,
@@ -717,29 +723,40 @@ ensure_ttl_timer(State = #q{backing_queue = BQ,
717723ensure_ttl_timer (State ) ->
718724 State .
719725
726+ ack_if_no_dlx (AckTags , State = # q {dlx = undefined ,
727+ backing_queue = BQ ,
728+ backing_queue_state = BQS }) ->
729+ {_Guids , BQS1 } = BQ :ack (AckTags , BQS ),
730+ State # q {backing_queue_state = BQS1 };
731+ ack_if_no_dlx (_AckTags , State ) ->
732+ State .
733+
720734dead_letter_fun (_Reason , # q {dlx = undefined }) ->
721735 undefined ;
722736dead_letter_fun (Reason , _State ) ->
723737 fun (Msg , AckTag ) ->
724738 gen_server2 :cast (self (), {dead_letter , {Msg , AckTag }, Reason })
725739 end .
726740
727- dead_letter_msg (Msg , AckTag , Reason , State = # q {dlx = DLX }) ->
728- case rabbit_exchange :lookup (DLX ) of
729- {error , not_found } -> noreply (State );
730- _ -> dead_letter_msg_existing_dlx (Msg , AckTag , Reason ,
731- State )
741+ dead_letter_publish (Msg , Reason , State = # q {publish_seqno = MsgSeqNo }) ->
742+ DLMsg = # basic_message {exchange_name = XName } =
743+ make_dead_letter_msg (Reason , Msg , State ),
744+ case rabbit_exchange :lookup (XName ) of
745+ {ok , X } ->
746+ Delivery = rabbit_basic :delivery (false , false , DLMsg , MsgSeqNo ),
747+ {Queues , Cycles } = detect_dead_letter_cycles (
748+ DLMsg , rabbit_exchange :route (X , Delivery )),
749+ lists :foreach (fun log_cycle_once /1 , Cycles ),
750+ QPids = rabbit_amqqueue :lookup (Queues ),
751+ {_ , DeliveredQPids } = rabbit_amqqueue :deliver (QPids , Delivery ),
752+ DeliveredQPids ;
753+ {error , not_found } ->
754+ []
732755 end .
733756
734- dead_letter_msg_existing_dlx (Msg , AckTag , Reason ,
735- State = # q {publish_seqno = MsgSeqNo ,
736- unconfirmed = UC ,
737- dlx = DLX }) ->
738- {ok , _ , QPids } =
739- rabbit_basic :publish (
740- rabbit_basic :delivery (
741- false , false , make_dead_letter_msg (DLX , Reason , Msg , State ),
742- MsgSeqNo )),
757+ dead_letter_msg (Msg , AckTag , Reason , State = # q {publish_seqno = MsgSeqNo ,
758+ unconfirmed = UC }) ->
759+ QPids = dead_letter_publish (Msg , Reason , State ),
743760 State1 = State # q {queue_monitors = pmon :monitor_all (
744761 QPids , State # q .queue_monitors ),
745762 publish_seqno = MsgSeqNo + 1 },
@@ -797,56 +814,58 @@ cleanup_after_confirm(AckTags, State = #q{delayed_stop = DS,
797814 false -> noreply (State1 )
798815 end .
799816
800- already_been_here (_Delivery , # q {dlx = undefined }) ->
801- false ;
802- already_been_here (# delivery {message = # basic_message {content = Content }},
803- State ) ->
817+ detect_dead_letter_cycles (# basic_message {content = Content }, Queues ) ->
804818 # content {properties = # 'P_basic' {headers = Headers }} =
805819 rabbit_binary_parser :ensure_content_decoded (Content ),
806- # resource { name = QueueName } = qname ( State ) ,
820+ NoCycles = { Queues , []} ,
807821 case Headers of
808822 undefined ->
809- false ;
823+ NoCycles ;
810824 _ ->
811825 case rabbit_misc :table_lookup (Headers , <<" x-death" >>) of
812826 {array , DeathTables } ->
813827 OldQueues = [rabbit_misc :table_lookup (D , <<" queue" >>) ||
814828 {table , D } <- DeathTables ],
815829 OldQueues1 = [QName || {longstr , QName } <- OldQueues ],
816- case lists :member (QueueName , OldQueues1 ) of
817- true -> [QueueName | OldQueues1 ];
818- _ -> false
819- end ;
830+ OldQueuesSet = ordsets :from_list (OldQueues1 ),
831+ {Cycling , NotCycling } =
832+ lists :partition (
833+ fun (Queue ) ->
834+ ordsets :is_element (Queue # resource .name ,
835+ OldQueuesSet )
836+ end , Queues ),
837+ {NotCycling , [[QName | OldQueues1 ] ||
838+ # resource {name = QName } <- Cycling ]};
820839 _ ->
821- false
840+ NoCycles
822841 end
823842 end .
824843
825- make_dead_letter_msg (DLX , Reason ,
844+ make_dead_letter_msg (Reason ,
826845 Msg = # basic_message {content = Content ,
827846 exchange_name = Exchange ,
828847 routing_keys = RoutingKeys },
829- State = # q {dlx_routing_key = DlxRoutingKey }) ->
848+ State = # q {dlx = DLX , dlx_routing_key = DlxRoutingKey }) ->
830849 {DeathRoutingKeys , HeadersFun1 } =
831850 case DlxRoutingKey of
832851 undefined -> {RoutingKeys , fun (H ) -> H end };
833852 _ -> {[DlxRoutingKey ],
834853 fun (H ) -> lists :keydelete (<<" CC" >>, 1 , H ) end }
835854 end ,
855+ ReasonBin = list_to_binary (atom_to_list (Reason )),
836856 # resource {name = QName } = qname (State ),
857+ TimeSec = rabbit_misc :now_ms () div 1000 ,
837858 HeadersFun2 =
838859 fun (Headers ) ->
839860 % % The first routing key is the one specified in the
840861 % % basic.publish; all others are CC or BCC keys.
841- RoutingKeys1 =
842- [hd (RoutingKeys ) | rabbit_basic :header_routes (Headers )],
843- Info = [{<<" reason" >>,
844- longstr , list_to_binary (atom_to_list (Reason ))},
845- {<<" queue" >>, longstr , QName },
846- {<<" time" >>, timestamp , rabbit_misc :now_ms () div 1000 },
847- {<<" exchange" >>, longstr , Exchange # resource .name },
848- {<<" routing-keys" >>, array ,
849- [{longstr , Key } || Key <- RoutingKeys1 ]}],
862+ RKs = [hd (RoutingKeys ) | rabbit_basic :header_routes (Headers )],
863+ RKs1 = [{longstr , Key } || Key <- RKs ],
864+ Info = [{<<" reason" >>, longstr , ReasonBin },
865+ {<<" queue" >>, longstr , QName },
866+ {<<" time" >>, timestamp , TimeSec },
867+ {<<" exchange" >>, longstr , Exchange # resource .name },
868+ {<<" routing-keys" >>, array , RKs1 }],
850869 HeadersFun1 (rabbit_basic :append_table_header (<<" x-death" >>,
851870 Info , Headers ))
852871 end ,
@@ -1196,8 +1215,7 @@ handle_cast(_, State = #q{delayed_stop = DS}) when DS =/= undefined ->
11961215handle_cast ({run_backing_queue , Mod , Fun }, State ) ->
11971216 noreply (run_backing_queue (Mod , Fun , State ));
11981217
1199- handle_cast ({deliver , Delivery = # delivery {sender = Sender ,
1200- msg_seq_no = MsgSeqNo }, Flow },
1218+ handle_cast ({deliver , Delivery = # delivery {sender = Sender }, Flow },
12011219 State = # q {senders = Senders }) ->
12021220 % % Asynchronous, non-"mandatory", non-"immediate" deliver mode.
12031221 Senders1 = case Flow of
@@ -1206,12 +1224,7 @@ handle_cast({deliver, Delivery = #delivery{sender = Sender,
12061224 noflow -> Senders
12071225 end ,
12081226 State1 = State # q {senders = Senders1 },
1209- case already_been_here (Delivery , State1 ) of
1210- false -> noreply (deliver_or_enqueue (Delivery , State1 ));
1211- Qs -> log_cycle_once (Qs ),
1212- rabbit_misc :confirm_to_sender (Sender , [MsgSeqNo ]),
1213- noreply (State1 )
1214- end ;
1227+ noreply (deliver_or_enqueue (Delivery , State1 ));
12151228
12161229handle_cast ({ack , AckTags , ChPid }, State ) ->
12171230 noreply (subtract_acks (
@@ -1227,11 +1240,13 @@ handle_cast({reject, AckTags, Requeue, ChPid}, State) ->
12271240 ChPid , AckTags , State ,
12281241 case Requeue of
12291242 true -> fun (State1 ) -> requeue_and_run (AckTags , State1 ) end ;
1230- false -> Fun = dead_letter_fun (rejected , State ),
1231- fun (State1 = # q {backing_queue = BQ ,
1243+ false -> fun (State1 = # q {backing_queue = BQ ,
12321244 backing_queue_state = BQS }) ->
1245+ Fun = dead_letter_fun (rejected , State1 ),
12331246 BQS1 = BQ :fold (Fun , BQS , AckTags ),
1234- State1 # q {backing_queue_state = BQS1 }
1247+ ack_if_no_dlx (
1248+ AckTags ,
1249+ State1 # q {backing_queue_state = BQS1 })
12351250 end
12361251 end ));
12371252
0 commit comments