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}