tower/retry/policy.rs
1use std::future::Future;
2
3/// A "retry policy" to classify if a request should be retried.
4///
5/// # Example
6///
7/// ```
8/// use tower::retry::Policy;
9/// use futures_util::future;
10///
11/// type Req = String;
12/// type Res = String;
13///
14/// struct Attempts(usize);
15///
16/// impl<E> Policy<Req, Res, E> for Attempts {
17/// type Future = future::Ready<()>;
18///
19/// fn retry(&mut self, req: &mut Req, result: &mut Result<Res, E>) -> Option<Self::Future> {
20/// match result {
21/// Ok(_) => {
22/// // Treat all `Response`s as success,
23/// // so don't retry...
24/// None
25/// },
26/// Err(_) => {
27/// // Treat all errors as failures...
28/// // But we limit the number of attempts...
29/// if self.0 > 0 {
30/// // Try again!
31/// self.0 -= 1;
32/// Some(future::ready(()))
33/// } else {
34/// // Used all our attempts, no retry...
35/// None
36/// }
37/// }
38/// }
39/// }
40///
41/// fn clone_request(&mut self, req: &Req) -> Option<Req> {
42/// Some(req.clone())
43/// }
44/// }
45/// ```
46pub trait Policy<Req, Res, E> {
47 /// The [`Future`] type returned by [`Policy::retry`].
48 type Future: Future<Output = ()>;
49
50 /// Check the policy if a certain request should be retried.
51 ///
52 /// This method is passed a reference to the original request, and either
53 /// the [`Service::Response`] or [`Service::Error`] from the inner service.
54 ///
55 /// If the request should **not** be retried, return `None`.
56 ///
57 /// If the request *should* be retried, return `Some` future that will delay
58 /// the next retry of the request. This can be used to sleep for a certain
59 /// duration, to wait for some external condition to be met before retrying,
60 /// or resolve right away, if the request should be retried immediately.
61 ///
62 /// ## Mutating Requests
63 ///
64 /// The policy MAY chose to mutate the `req`: if the request is mutated, the
65 /// mutated request will be sent to the inner service in the next retry.
66 /// This can be helpful for use cases like tracking the retry count in a
67 /// header.
68 ///
69 /// ## Mutating Results
70 ///
71 /// The policy MAY chose to mutate the result. This enables the retry
72 /// policy to convert a failure into a success and vice versa. For example,
73 /// if the policy is used to poll while waiting for a state change, the
74 /// policy can switch the result to emit a specific error when retries are
75 /// exhausted.
76 ///
77 /// The policy can also record metadata on the request to include
78 /// information about the number of retries required or to record that a
79 /// failure failed after exhausting all retries.
80 ///
81 /// [`Service::Response`]: crate::Service::Response
82 /// [`Service::Error`]: crate::Service::Error
83 fn retry(&mut self, req: &mut Req, result: &mut Result<Res, E>) -> Option<Self::Future>;
84
85 /// Tries to clone a request before being passed to the inner service.
86 ///
87 /// If the request cannot be cloned, return [`None`]. Moreover, the retry
88 /// function will not be called if the [`None`] is returned.
89 fn clone_request(&mut self, req: &Req) -> Option<Req>;
90}
91
92// Ensure `Policy` is object safe
93#[cfg(test)]
94fn _obj_safe(_: Box<dyn Policy<(), (), (), Future = futures::future::Ready<()>>>) {}