use std::fmt;
#[cfg(feature = "tokio")]
use std::future::Future;
use qubit_error::BoxError;
#[cfg(feature = "tokio")]
use super::async_retry_runner::AsyncRetryRunner;
use super::attempt_cancel_token::AttemptCancelToken;
use super::retry_builder::RetryBuilder;
use super::retry_runner::RetryRunner;
use super::worker_retry_runner::WorkerRetryRunner;
use crate::event::{
RetryEvents,
RetryListeners,
};
use crate::{
RetryAfterHint,
RetryConfigError,
RetryError,
RetryOptions,
};
#[derive(Clone)]
pub struct Retry<E = BoxError> {
options: RetryOptions,
events: RetryEvents<E>,
}
#[allow(clippy::result_large_err)]
impl<E> Retry<E> {
#[inline]
pub fn builder() -> RetryBuilder<E> {
RetryBuilder::new()
}
pub fn from_options(options: RetryOptions) -> Result<Self, RetryConfigError> {
Self::builder().options(options).build()
}
#[inline]
pub fn options(&self) -> &RetryOptions {
&self.options
}
pub fn run<T, F>(&self, operation: F) -> Result<T, RetryError<E>>
where
F: FnMut() -> Result<T, E>,
{
RetryRunner::new(self).run(operation)
}
#[cfg(feature = "tokio")]
pub async fn run_async<T, F, Fut>(&self, operation: F) -> Result<T, RetryError<E>>
where
F: FnMut() -> Fut,
Fut: Future<Output = Result<T, E>>,
{
AsyncRetryRunner::new(self).run(operation).await
}
pub fn run_in_worker<T, F>(&self, operation: F) -> Result<T, RetryError<E>>
where
T: Send + 'static,
E: Send + 'static,
F: Fn(AttemptCancelToken) -> Result<T, E> + Send + Sync + 'static,
{
WorkerRetryRunner::new(self).run(operation)
}
pub(super) fn new(
options: RetryOptions,
retry_after_hint: Option<RetryAfterHint<E>>,
isolate_listener_panics: bool,
listeners: RetryListeners<E>,
) -> Self {
Self {
options,
events: RetryEvents::new(retry_after_hint, isolate_listener_panics, listeners),
}
}
#[inline]
pub(in crate::executor) fn events(&self) -> &RetryEvents<E> {
&self.events
}
}
impl<E> fmt::Debug for Retry<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Retry")
.field("options", &self.options)
.finish_non_exhaustive()
}
}