| //! Service load measurement | |
| //! | |
| //! This module provides the [`Load`] trait, which allows measuring how loaded a service is. | |
| //! It also provides several wrapper types that measure load in different ways: | |
| //! | |
| //! - [`Constant`] — Always returns the same constant load value for a service. | |
| //! - [`PendingRequests`] — Measures load by tracking the number of in-flight requests. | |
| //! - [`PeakEwma`] — Measures load using a moving average of the peak latency for the service. | |
| //! | |
| //! In general, you will want to use one of these when using the types in [`tower::balance`] which | |
| //! balance services depending on their load. Which load metric to use depends on your exact | |
| //! use-case, but the ones above should get you quite far! | |
| //! | |
| //! When the `discover` feature is enabled, wrapper types for [`Discover`] that | |
| //! wrap the discovered services with the given load estimator are also provided. | |
| //! | |
| //! # When does a request complete? | |
| //! | |
| //! For many applications, the request life-cycle is relatively simple: when a service responds to | |
| //! a request, that request is done, and the system can forget about it. However, for some | |
| //! applications, the service may respond to the initial request while other parts of the system | |
| //! are still acting on that request. In such an application, the system load must take these | |
| //! requests into account as well, or risk the system underestimating its own load. | |
| //! | |
| //! To support these use-cases, the load estimators in this module are parameterized by the | |
| //! [`TrackCompletion`] trait, with [`CompleteOnResponse`] as the default type. The behavior of | |
| //! [`CompleteOnResponse`] is what you would normally expect for a request-response cycle: when the | |
| //! response is produced, the request is considered "finished", and load goes down. This can be | |
| //! overriden by your own user-defined type to track more complex request completion semantics. See | |
| //! the documentation for [`completion`] for more details. | |
| //! | |
| //! # Examples | |
| //! | |
| //! ```rust | |
| //! # #[cfg(feature = "util")] | |
| //! use tower::util::ServiceExt; | |
| //! # #[cfg(feature = "util")] | |
| //! use tower::{load::Load, Service}; | |
| //! # #[cfg(feature = "util")] | |
| //! async fn simple_balance<S1, S2, R>( | |
| //! svc1: &mut S1, | |
| //! svc2: &mut S2, | |
| //! request: R | |
| //! ) -> Result<S1::Response, S1::Error> | |
| //! where | |
| //! S1: Load + Service<R>, | |
| //! S2: Load<Metric = S1::Metric> + Service<R, Response = S1::Response, Error = S1::Error> | |
| //! { | |
| //! if svc1.load() < svc2.load() { | |
| //! svc1.ready().await?.call(request).await | |
| //! } else { | |
| //! svc2.ready().await?.call(request).await | |
| //! } | |
| //! } | |
| //! ``` | |
| //! | |
| //! [`tower::balance`]: crate::balance | |
| //! [`Discover`]: crate::discover::Discover | |
| //! [`CompleteOnResponse`]: crate::load::completion::CompleteOnResponse | |
| // TODO: a custom completion example would be good here | |
| pub mod completion; | |
| mod constant; | |
| pub mod peak_ewma; | |
| pub mod pending_requests; | |
| pub use self::{ | |
| completion::{CompleteOnResponse, TrackCompletion}, | |
| constant::Constant, | |
| peak_ewma::PeakEwma, | |
| pending_requests::PendingRequests, | |
| }; | |
| #[cfg(feature = "discover")] | |
| pub use self::{peak_ewma::PeakEwmaDiscover, pending_requests::PendingRequestsDiscover}; | |
| /// Types that implement this trait can give an estimate of how loaded they are. | |
| /// | |
| /// See the module documentation for more details. | |
| pub trait Load { | |
| /// A comparable load metric. | |
| /// | |
| /// Lesser values indicate that the service is less loaded, and should be preferred for new | |
| /// requests over another service with a higher value. | |
| type Metric: PartialOrd; | |
| /// Estimate the service's current load. | |
| fn load(&self) -> Self::Metric; | |
| } |