use std::fmt;
use std::time::Duration;
pub type ReconnectCallback = Box<dyn Fn(u32, &crate::error::PgError) + Send + Sync>;
#[non_exhaustive]
pub struct ReconnectConfig {
pub enabled: bool,
pub max_attempts: u32,
pub initial_delay: Duration,
pub max_delay: Duration,
pub rebuild_session: bool,
pub allow_mid_transaction: bool,
pub on_before_reconnect: Option<ReconnectCallback>,
}
impl Clone for ReconnectConfig {
fn clone(&self) -> Self {
ReconnectConfig {
enabled: self.enabled,
max_attempts: self.max_attempts,
initial_delay: self.initial_delay,
max_delay: self.max_delay,
rebuild_session: self.rebuild_session,
allow_mid_transaction: self.allow_mid_transaction,
on_before_reconnect: None, }
}
}
impl fmt::Debug for ReconnectConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReconnectConfig")
.field("enabled", &self.enabled)
.field("max_attempts", &self.max_attempts)
.field("initial_delay", &self.initial_delay)
.field("max_delay", &self.max_delay)
.field("rebuild_session", &self.rebuild_session)
.field("allow_mid_transaction", &self.allow_mid_transaction)
.field(
"on_before_reconnect",
&self.on_before_reconnect.as_ref().map(|_| "Some(callback)"),
)
.finish()
}
}
impl Default for ReconnectConfig {
fn default() -> Self {
ReconnectConfig {
enabled: false,
max_attempts: 3,
initial_delay: Duration::from_millis(100),
max_delay: Duration::from_secs(10),
rebuild_session: true,
allow_mid_transaction: false,
on_before_reconnect: None,
}
}
}
impl ReconnectConfig {
pub fn enabled() -> Self {
ReconnectConfig {
enabled: true,
..ReconnectConfig::default()
}
}
pub fn max_attempts(mut self, n: u32) -> Self {
self.max_attempts = n;
self
}
pub fn initial_delay(mut self, delay: Duration) -> Self {
self.initial_delay = delay;
self
}
pub fn max_delay(mut self, delay: Duration) -> Self {
self.max_delay = delay;
self
}
pub fn rebuild_session(mut self, rebuild: bool) -> Self {
self.rebuild_session = rebuild;
self
}
pub fn allow_mid_transaction(mut self, allow: bool) -> Self {
self.allow_mid_transaction = allow;
self
}
pub fn delay_for_attempt(&self, attempt: u32) -> Duration {
let multiplier = 2u32.saturating_pow(attempt.saturating_sub(1));
let delay = self.initial_delay * multiplier;
delay.min(self.max_delay)
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct StaleConfig {
pub stale_threshold: Duration,
pub ping_on_stale: bool,
}
impl Default for StaleConfig {
fn default() -> Self {
StaleConfig {
stale_threshold: Duration::from_secs(30),
ping_on_stale: true,
}
}
}
impl StaleConfig {
pub fn stale_threshold(mut self, threshold: Duration) -> Self {
self.stale_threshold = threshold;
self
}
pub fn ping_on_stale(mut self, ping: bool) -> Self {
self.ping_on_stale = ping;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reconnect_config_default() {
let config = ReconnectConfig::default();
assert!(!config.enabled);
assert_eq!(config.max_attempts, 3);
assert_eq!(config.initial_delay, Duration::from_millis(100));
assert_eq!(config.max_delay, Duration::from_secs(10));
assert!(config.rebuild_session);
assert!(!config.allow_mid_transaction);
assert!(config.on_before_reconnect.is_none());
}
#[test]
fn test_reconnect_config_enabled() {
let config = ReconnectConfig::enabled();
assert!(config.enabled);
}
#[test]
fn test_reconnect_config_builder() {
let config = ReconnectConfig::enabled()
.max_attempts(5)
.initial_delay(Duration::from_millis(200))
.max_delay(Duration::from_secs(30))
.rebuild_session(false)
.allow_mid_transaction(true);
assert!(config.enabled);
assert_eq!(config.max_attempts, 5);
assert_eq!(config.initial_delay, Duration::from_millis(200));
assert_eq!(config.max_delay, Duration::from_secs(30));
assert!(!config.rebuild_session);
assert!(config.allow_mid_transaction);
}
#[test]
fn test_reconnect_delay_for_attempt() {
let config = ReconnectConfig::default();
assert_eq!(config.delay_for_attempt(1), Duration::from_millis(100));
assert_eq!(config.delay_for_attempt(2), Duration::from_millis(200));
assert_eq!(config.delay_for_attempt(3), Duration::from_millis(400));
assert_eq!(config.delay_for_attempt(7), Duration::from_millis(6400));
assert_eq!(config.delay_for_attempt(8), Duration::from_secs(10));
}
#[test]
fn test_stale_config_default() {
let config = StaleConfig::default();
assert_eq!(config.stale_threshold, Duration::from_secs(30));
assert!(config.ping_on_stale);
}
#[test]
fn test_stale_config_builder() {
let config = StaleConfig::default()
.stale_threshold(Duration::from_secs(60))
.ping_on_stale(false);
assert_eq!(config.stale_threshold, Duration::from_secs(60));
assert!(!config.ping_on_stale);
}
}