tower_async/retry/
mod.rs

1//! Middleware for retrying "failed" requests.
2
3pub mod budget;
4mod layer;
5mod policy;
6
7pub use self::layer::RetryLayer;
8pub use self::policy::Policy;
9
10use tower_async_service::Service;
11
12/// Configure retrying requests of "failed" responses.
13///
14/// A [`Policy`] classifies what is a "failed" response.
15#[derive(Clone, Debug)]
16pub struct Retry<P, S> {
17    policy: P,
18    service: S,
19}
20
21// ===== impl Retry =====
22
23impl<P, S> Retry<P, S> {
24    /// Retry the inner service depending on this [`Policy`].
25    pub fn new(policy: P, service: S) -> Self {
26        Retry { policy, service }
27    }
28
29    /// Get a reference to the inner service
30    pub fn get_ref(&self) -> &S {
31        &self.service
32    }
33
34    /// Consume `self`, returning the inner service
35    pub fn into_inner(self) -> S {
36        self.service
37    }
38}
39
40impl<P, S, Request> Service<Request> for Retry<P, S>
41where
42    P: Policy<Request, S::Response, S::Error>,
43    S: Service<Request>,
44{
45    type Response = S::Response;
46    type Error = S::Error;
47
48    async fn call(&self, mut request: Request) -> Result<Self::Response, Self::Error> {
49        loop {
50            let cloned_request = self.policy.clone_request(&request);
51            let mut result = self.service.call(request).await;
52            if let Some(mut req) = cloned_request {
53                if !self.policy.retry(&mut req, &mut result).await {
54                    return result;
55                }
56                request = req;
57            } else {
58                return result;
59            }
60        }
61    }
62}