postgres_notify/
error.rs

1use {std::time::Duration, thiserror::Error};
2
3#[derive(Debug, Error)]
4pub enum PGError {
5    #[error(transparent)]
6    Postgres(tokio_postgres::Error),
7    #[error("Query timed out after {0:?}")]
8    Timeout(Duration),
9    #[error("Failed to reconnect after {0} attempts")]
10    FailedToReconnect(u32),
11    #[error(transparent)]
12    Other(Box<dyn std::error::Error + 'static>),
13}
14
15impl PGError {
16    pub fn is_pg_connection_issue(&self) -> bool {
17        matches!(self, PGError::Postgres(e) if is_pg_connection_issue(e))
18    }
19    pub fn is_timeout(&self) -> bool {
20        matches!(self, PGError::Timeout(_))
21    }
22
23    pub fn other(err: impl std::error::Error + 'static) -> Self {
24        PGError::Other(Box::new(err))
25    }
26}
27
28impl From<tokio_postgres::Error> for PGError {
29    fn from(e: tokio_postgres::Error) -> Self {
30        PGError::Postgres(e)
31    }
32}
33
34///
35/// PRIVATE
36/// Returns true if the error is a connection issue.
37///
38pub(crate) fn is_pg_connection_issue(err: &tokio_postgres::Error) -> bool {
39    if err.is_closed() {
40        return true;
41    }
42    let code = err.code().map(|state| state.code()).unwrap_or_default();
43    if code.starts_with("08") || code.starts_with("57") {
44        return true;
45    }
46
47    let msg = err.to_string();
48    msg.starts_with("error connecting to server")
49        || msg.starts_with("timeout waiting for server")
50        || msg.starts_with("error communicating with the server")
51}