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<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/// ```
45pub 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
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`].
66 fn clone_request(&self, req: &Req) -> Option<Req>;
67}