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