11use  std:: thread; 
22
3+ use  flume:: TrySendError ; 
34use  futures_channel:: oneshot; 
45
56use  crate :: error:: Error ; 
@@ -24,6 +25,7 @@ type PrepareSender = oneshot::Sender<PrepareResult>;
2425#[ derive( Debug ) ]  
2526pub ( crate )  struct  ConnectionWorker  { 
2627    command_tx :  flume:: Sender < Command > , 
28+     join_handle :  Option < thread:: JoinHandle < ( ) > > , 
2729} 
2830
2931enum  Command  { 
@@ -53,15 +55,25 @@ enum Command {
5355    } , 
5456} 
5557
58+ impl  Drop  for  ConnectionWorker  { 
59+     fn  drop ( & mut  self )  { 
60+         self . shutdown_sync ( ) ; 
61+     } 
62+ } 
63+ 
5664impl  ConnectionWorker  { 
5765    pub  async  fn  establish ( options :  OdbcConnectOptions )  -> Result < Self ,  Error >  { 
58-         let  ( establish_tx ,  establish_rx )  = oneshot :: channel ( ) ; 
59- 
60-         thread:: Builder :: new ( ) 
66+         let  ( command_tx ,  command_rx )  = flume :: bounded ( 64 ) ; 
67+          let   ( conn_tx ,  conn_rx )  = oneshot :: channel ( ) ; 
68+         let  thread =  thread:: Builder :: new ( ) 
6169            . name ( "sqlx-odbc-conn" . into ( ) ) 
62-             . spawn ( move  || worker_thread_main ( options,  establish_tx ) ) ?; 
70+             . spawn ( move  || worker_thread_main ( options,  command_rx ,  conn_tx ) ) ?; 
6371
64-         establish_rx. await . map_err ( |_| Error :: WorkerCrashed ) ?
72+         conn_rx. await . map_err ( |_| Error :: WorkerCrashed ) ??; 
73+         Ok ( ConnectionWorker  { 
74+             command_tx, 
75+             join_handle :  Some ( thread) , 
76+         } ) 
6577    } 
6678
6779    pub ( crate )  async  fn  ping ( & mut  self )  -> Result < ( ) ,  Error >  { 
@@ -77,11 +89,24 @@ impl ConnectionWorker {
7789    pub ( crate )  fn  shutdown_sync ( & mut  self )  { 
7890        // Send shutdown command without waiting for response 
7991        // Use try_send to avoid any potential blocking in Drop 
80-         let  ( tx,  _rx)  = oneshot:: channel ( ) ; 
81-         let  _ = self . command_tx . try_send ( Command :: Shutdown  {  tx } ) ; 
8292
83-         // Don't aggressively drop the channel to avoid SendError panics 
84-         // The worker thread will exit when it processes the Shutdown command 
93+         if  let  Some ( join_handle)  = self . join_handle . take ( )  { 
94+             let  ( mut  tx,  _rx)  = oneshot:: channel ( ) ; 
95+             while  let  Err ( TrySendError :: Full ( Command :: Shutdown  {  tx :  t } ) )  =
96+                 self . command_tx . try_send ( Command :: Shutdown  {  tx } ) 
97+             { 
98+                 tx = t; 
99+                 log:: warn!( "odbc worker thread queue is full, retrying..." ) ; 
100+                 thread:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) ; 
101+             } 
102+             if  let  Err ( e)  = join_handle. join ( )  { 
103+                 let  err = e. downcast_ref :: < std:: io:: Error > ( ) ; 
104+                 log:: error!( 
105+                     "failed to join worker thread while shutting down: {:?}" , 
106+                     err
107+                 ) ; 
108+             } 
109+         } 
85110    } 
86111
87112    pub ( crate )  async  fn  begin ( & mut  self )  -> Result < ( ) ,  Error >  { 
@@ -136,32 +161,22 @@ impl ConnectionWorker {
136161// Worker thread implementation 
137162fn  worker_thread_main ( 
138163    options :  OdbcConnectOptions , 
139-     establish_tx :  oneshot:: Sender < Result < ConnectionWorker ,  Error > > , 
164+     command_rx :  flume:: Receiver < Command > , 
165+     conn_tx :  oneshot:: Sender < Result < ( ) ,  Error > > , 
140166)  { 
141-     let  ( tx,  rx)  = flume:: bounded ( 64 ) ; 
142- 
143167    // Establish connection 
144168    let  conn = match  establish_connection ( & options)  { 
145-         Ok ( conn)  => conn, 
146-         Err ( e)  => { 
147-             let  _ = establish_tx. send ( Err ( e) ) ; 
148-             return ; 
169+         Ok ( conn)  => { 
170+             conn_tx. send ( Ok ( ( ) ) ) . unwrap ( ) ; 
171+             conn
149172        } 
173+         Err ( e)  => return  conn_tx. send ( Err ( e) ) . unwrap ( ) , 
150174    } ; 
151- 
152-     // Send back the worker handle 
153-     if  establish_tx
154-         . send ( Ok ( ConnectionWorker  { 
155-             command_tx :  tx. clone ( ) , 
156-         } ) ) 
157-         . is_err ( ) 
158-     { 
159-         return ; 
160-     } 
161- 
162175    // Process commands 
163-     while  let  Ok ( cmd)  = rx. recv ( )  { 
164-         if  !process_command ( cmd,  & conn)  { 
176+     while  let  Ok ( cmd)  = command_rx. recv ( )  { 
177+         if  let  Some ( shutdown_tx)  = process_command ( cmd,  & conn)  { 
178+             drop ( conn) ; 
179+             shutdown_tx. send ( ( ) ) . unwrap ( ) ; 
165180            break ; 
166181        } 
167182    } 
@@ -223,20 +238,18 @@ where
223238        . map_err ( |e| Error :: Protocol ( format ! ( "Failed to {} transaction: {}" ,  operation_name,  e) ) ) 
224239} 
225240
226- fn  process_command ( cmd :  Command ,  conn :  & OdbcConnection )  -> bool  { 
241+ // Returns a shutdown tx if the command is a shutdown command 
242+ fn  process_command ( cmd :  Command ,  conn :  & OdbcConnection )  -> Option < oneshot:: Sender < ( ) > >  { 
227243    match  cmd { 
228244        Command :: Ping  {  tx }  => handle_ping ( conn,  tx) , 
229245        Command :: Begin  {  tx }  => handle_begin ( conn,  tx) , 
230246        Command :: Commit  {  tx }  => handle_commit ( conn,  tx) , 
231247        Command :: Rollback  {  tx }  => handle_rollback ( conn,  tx) , 
232-         Command :: Shutdown  {  tx }  => { 
233-             let  _ = tx. send ( ( ) ) ; 
234-             return  false ;  // Signal to exit the loop 
235-         } 
248+         Command :: Shutdown  {  tx }  => return  Some ( tx) , 
236249        Command :: Execute  {  sql,  args,  tx }  => handle_execute ( conn,  sql,  args,  tx) , 
237250        Command :: Prepare  {  sql,  tx }  => handle_prepare ( conn,  sql,  tx) , 
238251    } 
239-     true 
252+     None 
240253} 
241254
242255// Command handlers 
0 commit comments