use std::task::{Context, Poll}; use tower::Service; use super::future::ResponseFuture; use crate::BoxedError; /// Provides fallback processing on a second service if the first service returned an error. #[derive(Debug)] pub struct Fallback where S2: Clone, { svc1: S1, svc2: S2, } impl Clone for Fallback { fn clone(&self) -> Self { Self { svc1: self.svc1.clone(), svc2: self.svc2.clone(), } } } impl Fallback { /// Creates a new `Fallback` wrapping a pair of services. /// /// Requests are processed on `svc1`, and retried on `svc2` if `svc1` errored. pub fn new(svc1: S1, svc2: S2) -> Self { Self { svc1, svc2 } } } impl Service for Fallback where S1: Service, S2: Service>::Response>, S1::Error: Into, S2::Error: Into, S2: Clone, Request: Clone, { type Response = >::Response; type Error = BoxedError; type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.svc1.poll_ready(cx).map_err(Into::into) } fn call(&mut self, request: Request) -> Self::Future { let request2 = request.clone(); ResponseFuture::new(self.svc1.call(request), request2, self.svc2.clone()) } }