11use std:: fmt:: { self , Debug } ;
2- use std:: io;
32use std:: str:: from_utf8;
43
54use futures_channel:: mpsc;
@@ -258,10 +257,44 @@ impl PgListener {
258257 ///
259258 /// [`eager_reconnect`]: PgListener::eager_reconnect
260259 pub async fn try_recv ( & mut self ) -> Result < Option < PgNotification > , Error > {
260+ match self . recv_without_recovery ( ) . await {
261+ Ok ( notification) => Ok ( Some ( notification) ) ,
262+
263+ // The connection is dead, ensure that it is dropped,
264+ // update self state
265+ Err ( Error :: Io ( _) ) => {
266+ if let Some ( mut conn) = self . connection . take ( ) {
267+ self . buffer_tx = conn. inner . stream . notifications . take ( ) ;
268+ // Close the connection in a background task, so we can continue.
269+ conn. close_on_drop ( ) ;
270+ }
271+
272+ if self . eager_reconnect {
273+ // If reconnecting fails due to an IO error - retry
274+ // if the pool is unable to get a new working connection
275+ // it will eventually error out with Error::PoolTimedOut and
276+ // end this loop
277+ loop {
278+ match self . connection ( ) . await {
279+ Ok ( _) => break ,
280+ Err ( Error :: Io ( _) ) => continue ,
281+ Err ( e) => return Err ( e) ,
282+ }
283+ }
284+ }
285+
286+ // lost connection
287+ Ok ( None )
288+ }
289+ Err ( e) => Err ( e) ,
290+ }
291+ }
292+
293+ async fn recv_without_recovery ( & mut self ) -> Result < PgNotification , Error > {
261294 // Flush the buffer first, if anything
262295 // This would only fill up if this listener is used as a connection
263296 if let Some ( notification) = self . next_buffered ( ) {
264- return Ok ( Some ( notification) ) ;
297+ return Ok ( notification) ;
265298 }
266299
267300 // Fetch our `CloseEvent` listener, if applicable.
@@ -278,45 +311,12 @@ impl PgListener {
278311 next_message. await
279312 } ;
280313
281- let message = match res {
282- Ok ( message) => message,
283-
284- // The connection is dead, ensure that it is dropped,
285- // update self state, and loop to try again.
286- Err ( Error :: Io ( err) )
287- if matches ! (
288- err. kind( ) ,
289- io:: ErrorKind :: ConnectionAborted |
290- io:: ErrorKind :: UnexpectedEof |
291- // see ERRORS section in tcp(7) man page (https://man7.org/linux/man-pages/man7/tcp.7.html)
292- io:: ErrorKind :: TimedOut |
293- io:: ErrorKind :: BrokenPipe
294- ) =>
295- {
296- if let Some ( mut conn) = self . connection . take ( ) {
297- self . buffer_tx = conn. inner . stream . notifications . take ( ) ;
298- // Close the connection in a background task, so we can continue.
299- conn. close_on_drop ( ) ;
300- }
301-
302- if self . eager_reconnect {
303- self . connect_if_needed ( ) . await ?;
304- }
305-
306- // lost connection
307- return Ok ( None ) ;
308- }
309-
310- // Forward other errors
311- Err ( error) => {
312- return Err ( error) ;
313- }
314- } ;
314+ let message = res?;
315315
316316 match message. format {
317317 // We've received an async notification, return it.
318318 BackendMessageFormat :: NotificationResponse => {
319- return Ok ( Some ( PgNotification ( message. decode ( ) ?) ) ) ;
319+ return Ok ( PgNotification ( message. decode ( ) ?) ) ;
320320 }
321321
322322 // Mark the connection as ready for another query
0 commit comments