use crate::Error;
pub const DEFAULT_MAX_RETRIES: u32 = 3;
#[cfg(feature = "sync")]
mod sync_impl {
use super::*;
pub trait ReconnectWaiter {
fn wait_connected(&self) -> Result<(), Error>;
}
impl ReconnectWaiter for crate::client::sync::Client {
fn wait_connected(&self) -> Result<(), Error> {
self.message_bus.wait_connected()
}
}
pub fn retry_on_connection_reset_with_limit<T, F>(waiter: &impl ReconnectWaiter, 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()?;
continue;
}
other => return other,
}
}
}
pub fn retry_on_connection_reset<T, F>(waiter: &impl ReconnectWaiter, operation: F) -> Result<T, Error>
where
F: FnMut() -> Result<T, Error>,
{
retry_on_connection_reset_with_limit(waiter, operation, DEFAULT_MAX_RETRIES)
}
}
#[cfg(feature = "async")]
mod async_impl {
use super::*;
use async_trait::async_trait;
use futures::Future;
#[async_trait]
pub trait ReconnectWaiter: Sync {
async fn wait_connected(&self) -> Result<(), Error>;
}
#[async_trait]
impl ReconnectWaiter for crate::client::r#async::Client {
async fn wait_connected(&self) -> Result<(), Error> {
self.message_bus.wait_connected().await
}
}
pub async fn retry_on_connection_reset_with_limit<T, F, Fut>(
waiter: &impl ReconnectWaiter,
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().await?;
continue;
}
other => return other,
}
}
}
pub async fn retry_on_connection_reset<T, F, Fut>(waiter: &impl ReconnectWaiter, operation: F) -> Result<T, Error>
where
F: FnMut() -> Fut,
Fut: Future<Output = Result<T, Error>>,
{
retry_on_connection_reset_with_limit(waiter, 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;