tower/retry/
mod.rs

1//! Middleware for retrying "failed" requests.
2
3pub mod backoff;
4pub mod budget;
5pub mod future;
6mod layer;
7mod policy;
8
9pub use self::layer::RetryLayer;
10pub use self::policy::Policy;
11
12use self::future::ResponseFuture;
13use pin_project_lite::pin_project;
14use std::task::{Context, Poll};
15use tower_service::Service;
16
17pin_project! {
18    /// Configure retrying requests of "failed" responses.
19    ///
20    /// A [`Policy`] classifies what is a "failed" response.
21    ///
22    /// # Clone
23    ///
24    /// This middleware requires that the inner `Service` implements [`Clone`],
25    /// because the `Service` must be stored in each [`ResponseFuture`] in
26    /// order to retry the request in the event of a failure. If the inner
27    /// `Service` type does not implement `Clone`, the [`Buffer`] middleware
28    /// can be added to make any `Service` cloneable.
29    ///
30    /// [`Buffer`]: crate::buffer::Buffer
31    ///
32    /// The `Policy` must also implement `Clone`. This middleware will
33    /// clone the policy for each _request session_. This means a new clone
34    /// of the policy will be created for each initial request and any subsequent
35    /// retries of that request. Therefore, any state stored in the `Policy` instance
36    /// is for that request session only. In order to share data across request
37    /// sessions, that shared state may be stored in an [`Arc`], so that all clones
38    /// of the `Policy` type reference the same instance of the shared state.
39    ///
40    /// [`Arc`]: std::sync::Arc
41    #[derive(Clone, Debug)]
42    pub struct Retry<P, S> {
43        policy: P,
44        service: S,
45    }
46}
47
48// ===== impl Retry =====
49
50impl<P, S> Retry<P, S> {
51    /// Retry the inner service depending on this [`Policy`].
52    pub const fn new(policy: P, service: S) -> Self {
53        Retry { policy, service }
54    }
55
56    /// Get a reference to the inner service
57    pub fn get_ref(&self) -> &S {
58        &self.service
59    }
60
61    /// Get a mutable reference to the inner service
62    pub fn get_mut(&mut self) -> &mut S {
63        &mut self.service
64    }
65
66    /// Consume `self`, returning the inner service
67    pub fn into_inner(self) -> S {
68        self.service
69    }
70}
71
72impl<P, S, Request> Service<Request> for Retry<P, S>
73where
74    P: Policy<Request, S::Response, S::Error> + Clone,
75    S: Service<Request> + Clone,
76{
77    type Response = S::Response;
78    type Error = S::Error;
79    type Future = ResponseFuture<P, S, Request>;
80
81    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
82        // NOTE: the Future::poll impl for ResponseFuture assumes that Retry::poll_ready is
83        // equivalent to Ready.service.poll_ready. If this ever changes, that code must be updated
84        // as well.
85        self.service.poll_ready(cx)
86    }
87
88    fn call(&mut self, request: Request) -> Self::Future {
89        let cloned = self.policy.clone_request(&request);
90        let future = self.service.call(request);
91
92        ResponseFuture::new(cloned, self.clone(), future)
93    }
94}