tower/retry/
mod.rs

1//! Middleware for retrying "failed" requests.
2
3pub mod budget;
4pub mod future;
5mod layer;
6mod policy;
7
8pub use self::layer::RetryLayer;
9pub use self::policy::Policy;
10
11use self::future::ResponseFuture;
12use pin_project_lite::pin_project;
13use std::task::{Context, Poll};
14use tower_service::Service;
15
16pin_project! {
17    /// Configure retrying requests of "failed" responses.
18    ///
19    /// A [`Policy`] classifies what is a "failed" response.
20    #[derive(Clone, Debug)]
21    pub struct Retry<P, S> {
22        #[pin]
23        policy: P,
24        service: S,
25    }
26}
27
28// ===== impl Retry =====
29
30impl<P, S> Retry<P, S> {
31    /// Retry the inner service depending on this [`Policy`].
32    pub fn new(policy: P, service: S) -> Self {
33        Retry { policy, service }
34    }
35
36    /// Get a reference to the inner service
37    pub fn get_ref(&self) -> &S {
38        &self.service
39    }
40
41    /// Get a mutable reference to the inner service
42    pub fn get_mut(&mut self) -> &mut S {
43        &mut self.service
44    }
45
46    /// Consume `self`, returning the inner service
47    pub fn into_inner(self) -> S {
48        self.service
49    }
50}
51
52impl<P, S, Request> Service<Request> for Retry<P, S>
53where
54    P: Policy<Request, S::Response, S::Error> + Clone,
55    S: Service<Request> + Clone,
56{
57    type Response = S::Response;
58    type Error = S::Error;
59    type Future = ResponseFuture<P, S, Request>;
60
61    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
62        // NOTE: the Future::poll impl for ResponseFuture assumes that Retry::poll_ready is
63        // equivalent to Ready.service.poll_ready. If this ever changes, that code must be updated
64        // as well.
65        self.service.poll_ready(cx)
66    }
67
68    fn call(&mut self, request: Request) -> Self::Future {
69        let cloned = self.policy.clone_request(&request);
70        let future = self.service.call(request);
71
72        ResponseFuture::new(cloned, self.clone(), future)
73    }
74}