@@ -14,7 +14,7 @@ use crate::error::DBError;
1414use crate :: host:: module_host:: ClientConnectedError ;
1515use crate :: host:: {
1616 CallProcedureReturn , FunctionArgs , ModuleHost , NoSuchModule , ProcedureCallResult , ReducerCallError ,
17- ReducerCallResult ,
17+ ReducerCallResult , ReducerOutcome ,
1818} ;
1919use crate :: subscription:: module_subscription_manager:: BroadcastError ;
2020use crate :: subscription:: row_list_builder_pool:: JsonRowListBuilderFakePool ;
@@ -870,18 +870,33 @@ impl ClientConnection {
870870 timer : Instant ,
871871 _flags : ws_v2:: CallReducerFlags ,
872872 ) -> Result < ReducerCallResult , ReducerCallError > {
873- self . module ( )
874- . call_reducer (
875- self . id . identity ,
876- Some ( self . id . connection_id ) ,
877- None ,
878- Some ( self . sender ( ) ) ,
879- Some ( request_id) ,
880- Some ( timer) ,
881- reducer,
882- FunctionArgs :: Bsatn ( args) ,
883- )
884- . await
873+ const MAX_WOUNDED_RETRIES : usize = 3 ;
874+
875+ let module = self . module ( ) ;
876+ let mut tx_id = module. replica_ctx ( ) . mint_global_tx_id ( Timestamp :: now ( ) ) ;
877+
878+ for attempt in 0 ..=MAX_WOUNDED_RETRIES {
879+ let result = module
880+ . call_reducer (
881+ self . id . identity ,
882+ Some ( self . id . connection_id ) ,
883+ Some ( tx_id) ,
884+ Some ( self . sender ( ) ) ,
885+ Some ( request_id) ,
886+ Some ( timer) ,
887+ reducer,
888+ FunctionArgs :: Bsatn ( args. clone ( ) ) ,
889+ )
890+ . await ?;
891+
892+ if !matches ! ( result. outcome, ReducerOutcome :: Wounded ( _) ) || attempt == MAX_WOUNDED_RETRIES {
893+ return Ok ( result) ;
894+ }
895+
896+ tx_id = tx_id. next_attempt ( ) ;
897+ }
898+
899+ unreachable ! ( "retry loop should return before exhausting attempts" )
885900 }
886901
887902 pub async fn call_procedure (
0 commit comments