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