Skip to content

Commit 4fec466

Browse files
authored
Fix PgListener::try_recv (#4016)
* remove specific IO error kind matching in PgListener::try_recv * add dbg! to identify where the error is coming from * rewrite PgListener recv and try_recv methods * fix fmt and clippy * remove the redundant backoff logic
1 parent 8b65c2f commit 4fec466

1 file changed

Lines changed: 37 additions & 37 deletions

File tree

‎sqlx-postgres/src/listener.rs‎

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::fmt::{self, Debug};
2-
use std::io;
32
use std::str::from_utf8;
43

54
use 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

Comments
 (0)