@@ -651,21 +651,61 @@ update_durable_in_mnesia(UpdateFun, FilterFun) ->
651651 ok .
652652
653653update_durable_in_khepri (UpdateFun , FilterFun ) ->
654- Path = khepri_queues_path () ++ [rabbit_khepri :if_has_data_wildcard ()],
655- rabbit_khepri :transaction (
656- fun () ->
657- khepri_tx :foreach (Path ,
658- fun (Path0 , #{data := Q }) ->
659- DoUpdate = amqqueue :is_durable (Q )
660- andalso FilterFun (Q ),
661- case DoUpdate of
662- true ->
663- khepri_tx :put (Path0 , UpdateFun (Q ));
664- false ->
665- ok
666- end
667- end )
668- end ).
654+ PathPattern = khepri_queues_path () ++
655+ [? KHEPRI_WILDCARD_STAR ,
656+ # if_data_matches {
657+ pattern = amqqueue :pattern_match_on_durable (true )}],
658+ % % The `FilterFun' or `UpdateFun' might attempt to do something
659+ % % incompatible with Khepri transactions (such as dynamic apply, sending
660+ % % a message, etc.), so this function cannot be written as a regular
661+ % % transaction. Instead we can get all queues and track their versions,
662+ % % update them, then apply the updates in a transaction, failing if any
663+ % % queue has changed since reading the queue record.
664+ case rabbit_khepri :adv_get_many (PathPattern ) of
665+ {ok , Props } ->
666+ Updates = maps :fold (
667+ fun (Path0 , #{data := Q0 , payload_version := Vsn }, Acc )
668+ when ? is_amqqueue (Q0 ) ->
669+ case FilterFun (Q0 ) of
670+ true ->
671+ Path = khepri_path :combine_with_conditions (
672+ Path0 ,
673+ [# if_payload_version {version = Vsn }]),
674+ Q = UpdateFun (Q0 ),
675+ [{Path , Q } | Acc ];
676+ false ->
677+ Acc
678+ end
679+ end , [], Props ),
680+ Res = rabbit_khepri :transaction (
681+ fun () ->
682+ for_each_while_ok (
683+ fun ({Path , Q }) -> khepri_tx :put (Path , Q ) end ,
684+ Updates )
685+ end ),
686+ case Res of
687+ ok ->
688+ ok ;
689+ {error , {khepri , mismatching_node , _ }} ->
690+ % % One of the queues changed while attempting to update
691+ % % all queues. Retry the operation.
692+ update_durable_in_khepri (UpdateFun , FilterFun );
693+ {error , _ } = Error ->
694+ Error
695+ end ;
696+ {error , _ } = Error ->
697+ Error
698+ end .
699+
700+ for_each_while_ok (Fun , [Elem | Rest ]) ->
701+ case Fun (Elem ) of
702+ ok ->
703+ for_each_while_ok (Fun , Rest );
704+ {error , _ } = Error ->
705+ Error
706+ end ;
707+ for_each_while_ok (_ , []) ->
708+ ok .
669709
670710% % -------------------------------------------------------------------
671711% % exists().
0 commit comments