1- use std:: {
2- future:: Future ,
3- sync:: {
4- atomic:: { AtomicBool , Ordering } ,
5- Arc ,
6- } ,
7- time:: Duration ,
8- } ;
1+ use std:: { future:: Future , sync:: Arc , time:: Duration } ;
92
103use sqlx:: { postgres:: PgPoolOptions , Pool , Postgres } ;
114
@@ -21,8 +14,6 @@ enum Operation {
2114#[ derive( Debug ) ]
2215struct DbNode {
2316 pool : Pool < Postgres > ,
24- last_read_failed : AtomicBool ,
25- last_write_failed : AtomicBool ,
2617}
2718
2819/// Database orchestrator for running reads/writes across multiple PostgreSQL nodes with retry/backoff.
@@ -77,11 +68,7 @@ impl DbOrchestrator {
7768 . map ( |url| {
7869 let pool = PgPoolOptions :: new ( ) . max_connections ( 5 ) . connect_lazy ( url) ?;
7970
80- Ok ( Arc :: new ( DbNode {
81- pool,
82- last_read_failed : AtomicBool :: new ( false ) ,
83- last_write_failed : AtomicBool :: new ( false ) ,
84- } ) )
71+ Ok ( Arc :: new ( DbNode { pool } ) )
8572 } )
8673 . collect :: < Result < Vec < _ > , sqlx:: Error > > ( )
8774 . map_err ( DbOrchestratorError :: Sqlx ) ?;
@@ -92,23 +79,7 @@ impl DbOrchestrator {
9279 } )
9380 }
9481
95- pub async fn write < T , Q , Fut > ( & self , query : Q ) -> Result < T , sqlx:: Error >
96- where
97- Q : Fn ( Pool < Postgres > ) -> Fut ,
98- Fut : Future < Output = Result < T , sqlx:: Error > > ,
99- {
100- self . query :: < T , Q , Fut > ( query, Operation :: Write ) . await
101- }
102-
103- pub async fn read < T , Q , Fut > ( & self , query : Q ) -> Result < T , sqlx:: Error >
104- where
105- Q : Fn ( Pool < Postgres > ) -> Fut ,
106- Fut : Future < Output = Result < T , sqlx:: Error > > ,
107- {
108- self . query :: < T , Q , Fut > ( query, Operation :: Read ) . await
109- }
110-
111- async fn query < T , Q , Fut > ( & self , query_fn : Q , operation : Operation ) -> Result < T , sqlx:: Error >
82+ pub async fn query < T , Q , Fut > ( & self , query_fn : Q ) -> Result < T , sqlx:: Error >
11283 where
11384 Q : Fn ( Pool < Postgres > ) -> Fut ,
11485 Fut : Future < Output = Result < T , sqlx:: Error > > ,
@@ -117,7 +88,7 @@ impl DbOrchestrator {
11788 let mut delay = Duration :: from_millis ( self . retry_config . min_delay_millis ) ;
11889
11990 loop {
120- match self . execute_once ( & query_fn, operation ) . await {
91+ match self . execute_once ( & query_fn) . await {
12192 Ok ( value) => return Ok ( value) ,
12293 Err ( RetryError :: Permanent ( err) ) => return Err ( err) ,
12394 Err ( RetryError :: Transient ( err) ) => {
@@ -134,38 +105,23 @@ impl DbOrchestrator {
134105 }
135106 }
136107
137- async fn execute_once < T , Q , Fut > (
138- & self ,
139- query_fn : & Q ,
140- operation : Operation ,
141- ) -> Result < T , RetryError < sqlx:: Error > >
108+ async fn execute_once < T , Q , Fut > ( & self , query_fn : & Q ) -> Result < T , RetryError < sqlx:: Error > >
142109 where
143110 Q : Fn ( Pool < Postgres > ) -> Fut ,
144111 Fut : Future < Output = Result < T , sqlx:: Error > > ,
145112 {
146113 let mut last_error = None ;
147114
148- for idx in self . preferred_order ( operation) {
149- let node = & self . nodes [ idx] ;
115+ for ( idx, node) in self . nodes . iter ( ) . enumerate ( ) {
150116 let pool = node. pool . clone ( ) ;
151117
152118 match query_fn ( pool) . await {
153119 Ok ( res) => {
154- match operation {
155- Operation :: Read => node. last_read_failed . store ( false , Ordering :: Relaxed ) ,
156- Operation :: Write => node. last_write_failed . store ( false , Ordering :: Relaxed ) ,
157- } ;
158120 return Ok ( res) ;
159121 }
160122 Err ( err) => {
161123 if Self :: is_connection_error ( & err) {
162124 tracing:: warn!( node_index = idx, error = ?err, "database query failed" ) ;
163- match operation {
164- Operation :: Read => node. last_read_failed . store ( true , Ordering :: Relaxed ) ,
165- Operation :: Write => {
166- node. last_write_failed . store ( true , Ordering :: Relaxed )
167- }
168- } ;
169125 last_error = Some ( err) ;
170126 } else {
171127 return Err ( RetryError :: Permanent ( err) ) ;
@@ -179,27 +135,6 @@ impl DbOrchestrator {
179135 ) )
180136 }
181137
182- fn preferred_order ( & self , operation : Operation ) -> Vec < usize > {
183- let mut preferred = Vec :: with_capacity ( self . nodes . len ( ) ) ;
184- let mut fallback = Vec :: new ( ) ;
185-
186- for ( idx, node) in self . nodes . iter ( ) . enumerate ( ) {
187- let failed = match operation {
188- Operation :: Read => node. last_read_failed . load ( Ordering :: Relaxed ) ,
189- Operation :: Write => node. last_write_failed . load ( Ordering :: Relaxed ) ,
190- } ;
191-
192- if failed {
193- fallback. push ( idx) ;
194- } else {
195- preferred. push ( idx) ;
196- }
197- }
198-
199- preferred. extend ( fallback) ;
200- preferred
201- }
202-
203138 fn is_connection_error ( error : & sqlx:: Error ) -> bool {
204139 matches ! (
205140 error,
0 commit comments