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}