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}
12
13impl PGError {
14 pub fn is_pg_connection_issue(&self) -> bool {
15 matches!(self, PGError::Postgres(e) if is_pg_connection_issue(e))
16 }
17 pub fn is_timeout(&self) -> bool {
18 matches!(self, PGError::Timeout(_))
19 }
20}
21
22impl From<tokio_postgres::Error> for PGError {
23 fn from(e: tokio_postgres::Error) -> Self {
24 PGError::Postgres(e)
25 }
26}
27
28pub(crate) fn is_pg_connection_issue(err: &tokio_postgres::Error) -> bool {
33 if err.is_closed() {
34 return true;
35 }
36 let code = err.code().map(|state| state.code()).unwrap_or_default();
37 if code.starts_with("08") || code.starts_with("57") {
38 return true;
39 }
40
41 let msg = err.to_string();
42 msg.starts_with("error connecting to server")
43 || msg.starts_with("timeout waiting for server")
44 || msg.starts_with("error communicating with the server")
45}