Skip to main content

adventure/retry/
mod.rs

1pub mod backoff;
2#[cfg(feature = "tokio-timer")]
3pub mod tokio;
4
5mod error;
6mod impls;
7
8use core::ops::Deref;
9use core::pin::Pin;
10use core::time::Duration;
11
12use crate::request::BaseRequest;
13use crate::response::Response;
14
15#[cfg(feature = "tokio-timer")]
16#[doc(inline)]
17pub use self::tokio::TokioTimer;
18pub use self::{
19    backoff::{Backoff, ExponentialBackoff},
20    error::RetryError,
21    impls::{Retrial, RetrialPredicate, Retrying},
22};
23
24#[cfg(feature = "tokio-timer")]
25pub type RetryingTokio<R, B = ExponentialBackoff, F = ()> = Retrying<R, TokioTimer, B, F>;
26
27/// A request able to decide to send itself again if the previous attempt has failed.
28pub trait RetriableRequest: BaseRequest {
29    fn should_retry(&self, error: &Self::Error, next_interval: Duration) -> bool;
30
31    /// Wrap this request to retry itself on failure, with a default [`ExponentialBackoff`] strategy.
32    ///
33    /// It should be called within the tokio execution context,
34    /// because the default timer is implemented using [`tokio_timer`].
35    #[cfg(feature = "tokio-timer")]
36    fn retry(self) -> RetryingTokio<Self>
37    where
38        Self: Sized,
39    {
40        RetryingTokio::from_default(self)
41    }
42
43    /// Wrap this request to retry itself on failure, with a given backoff strategy.
44    ///
45    /// It should be called within the tokio execution context,
46    /// because the default timer is implemented using [`tokio_timer`].
47    #[cfg(feature = "tokio-timer")]
48    fn retry_with_backoff<B>(self, backoff: B) -> RetryingTokio<Self, B>
49    where
50        Self: BaseRequest + Sized,
51        B: Backoff,
52    {
53        RetryingTokio::new(self, Default::default(), backoff)
54    }
55}
56
57impl<R> RetriableRequest for &R
58where
59    R: RetriableRequest,
60{
61    fn should_retry(&self, error: &Self::Error, next_interval: Duration) -> bool {
62        (*self).should_retry(error, next_interval)
63    }
64}
65
66impl<P> RetriableRequest for Pin<P>
67where
68    P: Deref,
69    <P as Deref>::Target: RetriableRequest,
70{
71    fn should_retry(&self, error: &Self::Error, next_interval: Duration) -> bool {
72        <<P as Deref>::Target>::should_retry(self, error, next_interval)
73    }
74}
75
76pub trait Timer {
77    type Delay: Response<Ok = (), Error = RetryError>;
78
79    fn expires_in(&mut self, interval: Duration) -> Self::Delay;
80}
81
82#[cfg(feature = "alloc")]
83mod feature_alloc {
84    use alloc::boxed::Box;
85
86    use super::*;
87
88    impl<R> RetriableRequest for Box<R>
89    where
90        R: RetriableRequest,
91    {
92        fn should_retry(&self, error: &Self::Error, next_interval: Duration) -> bool {
93            (**self).should_retry(error, next_interval)
94        }
95    }
96}