1 use 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<Self>;
18 ///
19 ///     fn retry(&self, req: &Req, result: 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 ///                     Some(future::ready(Attempts(self.0 - 1)))
32 ///                 } else {
33 ///                     // Used all our attempts, no retry...
34 ///                     None
35 ///                 }
36 ///             }
37 ///         }
38 ///     }
39 ///
40 ///     fn clone_request(&self, req: &Req) -> Option<Req> {
41 ///         Some(req.clone())
42 ///     }
43 /// }
44 /// ```
45 pub trait Policy<Req, Res, E>: Sized {
46     /// The [`Future`] type returned by [`Policy::retry`].
47     type Future: Future<Output = Self>;
48 
49     /// Check the policy if a certain request should be retried.
50     ///
51     /// This method is passed a reference to the original request, and either
52     /// the [`Service::Response`] or [`Service::Error`] from the inner service.
53     ///
54     /// If the request should **not** be retried, return `None`.
55     ///
56     /// If the request *should* be retried, return `Some` future of a new
57     /// policy that would apply for the next request attempt.
58     ///
59     /// [`Service::Response`]: crate::Service::Response
60     /// [`Service::Error`]: crate::Service::Error
retry(&self, req: &Req, result: Result<&Res, &E>) -> Option<Self::Future>61     fn retry(&self, req: &Req, result: Result<&Res, &E>) -> Option<Self::Future>;
62 
63     /// Tries to clone a request before being passed to the inner service.
64     ///
65     /// If the request cannot be cloned, return [`None`].
clone_request(&self, req: &Req) -> Option<Req>66     fn clone_request(&self, req: &Req) -> Option<Req>;
67 }
68