tower_fallback/
service.rs

1use std::task::{Context, Poll};
2
3use tower::Service;
4
5use super::future::ResponseFuture;
6use crate::BoxedError;
7
8/// Provides fallback processing on a second service if the first service returned an error.
9#[derive(Debug)]
10pub struct Fallback<S1, S2>
11where
12    S2: Clone,
13{
14    svc1: S1,
15    svc2: S2,
16}
17
18impl<S1: Clone, S2: Clone> Clone for Fallback<S1, S2> {
19    fn clone(&self) -> Self {
20        Self {
21            svc1: self.svc1.clone(),
22            svc2: self.svc2.clone(),
23        }
24    }
25}
26
27impl<S1, S2: Clone> Fallback<S1, S2> {
28    /// Creates a new `Fallback` wrapping a pair of services.
29    ///
30    /// Requests are processed on `svc1`, and retried on `svc2` if `svc1` errored.
31    pub fn new(svc1: S1, svc2: S2) -> Self {
32        Self { svc1, svc2 }
33    }
34}
35
36impl<S1, S2, Request> Service<Request> for Fallback<S1, S2>
37where
38    S1: Service<Request>,
39    S2: Service<Request, Response = <S1 as Service<Request>>::Response>,
40    S1::Error: Into<BoxedError>,
41    S2::Error: Into<BoxedError>,
42    S2: Clone,
43    Request: Clone,
44{
45    type Response = <S1 as Service<Request>>::Response;
46    type Error = BoxedError;
47    type Future = ResponseFuture<S1, S2, Request>;
48
49    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
50        self.svc1.poll_ready(cx).map_err(Into::into)
51    }
52
53    fn call(&mut self, request: Request) -> Self::Future {
54        let request2 = request.clone();
55        ResponseFuture::new(self.svc1.call(request), request2, self.svc2.clone())
56    }
57}