use crate::Error;
pub const DEFAULT_MAX_RETRIES: u32 = 3;
#[cfg(feature = "sync")]
mod sync_impl {
use super::*;
use std::time::Instant;
pub trait ReconnectWaiter {
fn wait_connected(&self, deadline: Option<Instant>) -> Result<(), Error>;
}
impl ReconnectWaiter for crate::client::sync::Client {
fn wait_connected(&self, deadline: Option<Instant>) -> Result<(), Error> {
self.message_bus.wait_connected(deadline)
}
}
pub fn retry_on_connection_reset_with_limit<T, F>(
waiter: &impl ReconnectWaiter,
deadline: Option<Instant>,
mut operation: F,
max_retries: u32,
) -> Result<T, Error>
where
F: FnMut() -> Result<T, Error>,
{
let mut attempts = 0;
loop {
match operation() {
Err(Error::ConnectionReset) if attempts < max_retries => {
attempts += 1;
waiter.wait_connected(deadline)?;
continue;
}
other => return other,
}
}
}
pub fn retry_on_connection_reset<T, F>(waiter: &impl ReconnectWaiter, deadline: Option<Instant>, operation: F) -> Result<T, Error>
where
F: FnMut() -> Result<T, Error>,
{
retry_on_connection_reset_with_limit(waiter, deadline, operation, DEFAULT_MAX_RETRIES)
}
}
#[cfg(feature = "async")]
mod async_impl {
use super::*;
use async_trait::async_trait;
use futures::Future;
use tokio::time::Instant;
#[async_trait]
pub trait ReconnectWaiter: Sync {
async fn wait_connected(&self, deadline: Option<Instant>) -> Result<(), Error>;
}
#[async_trait]
impl ReconnectWaiter for crate::client::r#async::Client {
async fn wait_connected(&self, deadline: Option<Instant>) -> Result<(), Error> {
self.message_bus.wait_connected(deadline).await
}
}
pub async fn retry_on_connection_reset_with_limit<T, F, Fut>(
waiter: &impl ReconnectWaiter,
deadline: Option<Instant>,
mut operation: F,
max_retries: u32,
) -> Result<T, Error>
where
F: FnMut() -> Fut,
Fut: Future<Output = Result<T, Error>>,
{
let mut attempts = 0;
loop {
match operation().await {
Err(Error::ConnectionReset) if attempts < max_retries => {
attempts += 1;
waiter.wait_connected(deadline).await?;
continue;
}
other => return other,
}
}
}
pub async fn retry_on_connection_reset<T, F, Fut>(waiter: &impl ReconnectWaiter, deadline: Option<Instant>, operation: F) -> Result<T, Error>
where
F: FnMut() -> Fut,
Fut: Future<Output = Result<T, Error>>,
{
retry_on_connection_reset_with_limit(waiter, deadline, operation, DEFAULT_MAX_RETRIES).await
}
}
#[cfg(feature = "sync")]
pub mod blocking {
pub(crate) use super::sync_impl::*;
}
#[cfg(all(feature = "sync", not(feature = "async")))]
#[allow(unused_imports)]
pub use sync_impl::*;
#[cfg(feature = "async")]
pub use async_impl::*;
#[cfg(test)]
#[path = "retry_tests.rs"]
mod tests;