1 //! Middleware for shedding load when inner services aren't ready.
2 
3 use std::task::{Context, Poll};
4 use tower_service::Service;
5 
6 pub mod error;
7 pub mod future;
8 mod layer;
9 
10 use self::future::ResponseFuture;
11 pub use self::layer::LoadShedLayer;
12 
13 /// A [`Service`] that sheds load when the inner service isn't ready.
14 ///
15 /// [`Service`]: crate::Service
16 #[derive(Debug)]
17 pub struct LoadShed<S> {
18     inner: S,
19     is_ready: bool,
20 }
21 
22 // ===== impl LoadShed =====
23 
24 impl<S> LoadShed<S> {
25     /// Wraps a service in [`LoadShed`] middleware.
new(inner: S) -> Self26     pub fn new(inner: S) -> Self {
27         LoadShed {
28             inner,
29             is_ready: false,
30         }
31     }
32 }
33 
34 impl<S, Req> Service<Req> for LoadShed<S>
35 where
36     S: Service<Req>,
37     S::Error: Into<crate::BoxError>,
38 {
39     type Response = S::Response;
40     type Error = crate::BoxError;
41     type Future = ResponseFuture<S::Future>;
42 
poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>43     fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
44         // We check for readiness here, so that we can know in `call` if
45         // the inner service is overloaded or not.
46         self.is_ready = match self.inner.poll_ready(cx) {
47             Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
48             r => r.is_ready(),
49         };
50 
51         // But we always report Ready, so that layers above don't wait until
52         // the inner service is ready (the entire point of this layer!)
53         Poll::Ready(Ok(()))
54     }
55 
call(&mut self, req: Req) -> Self::Future56     fn call(&mut self, req: Req) -> Self::Future {
57         if self.is_ready {
58             // readiness only counts once, you need to check again!
59             self.is_ready = false;
60             ResponseFuture::called(self.inner.call(req))
61         } else {
62             ResponseFuture::overloaded()
63         }
64     }
65 }
66 
67 impl<S: Clone> Clone for LoadShed<S> {
clone(&self) -> Self68     fn clone(&self) -> Self {
69         LoadShed {
70             inner: self.inner.clone(),
71             // new clones shouldn't carry the readiness state, as a cloneable
72             // inner service likely tracks readiness per clone.
73             is_ready: false,
74         }
75     }
76 }
77