tower/load/mod.rs
1//! Service load measurement
2//!
3//! This module provides the [`Load`] trait, which allows measuring how loaded a service is.
4//! It also provides several wrapper types that measure load in different ways:
5//!
6//! - [`Constant`] — Always returns the same constant load value for a service.
7//! - [`PendingRequests`] — Measures load by tracking the number of in-flight requests.
8//! - [`PeakEwma`] — Measures load using a moving average of the peak latency for the service.
9//!
10//! In general, you will want to use one of these when using the types in [`tower::balance`] which
11//! balance services depending on their load. Which load metric to use depends on your exact
12//! use-case, but the ones above should get you quite far!
13//!
14//! When the `discover` feature is enabled, wrapper types for [`Discover`] that
15//! wrap the discovered services with the given load estimator are also provided.
16//!
17//! # When does a request complete?
18//!
19//! For many applications, the request life-cycle is relatively simple: when a service responds to
20//! a request, that request is done, and the system can forget about it. However, for some
21//! applications, the service may respond to the initial request while other parts of the system
22//! are still acting on that request. In such an application, the system load must take these
23//! requests into account as well, or risk the system underestimating its own load.
24//!
25//! To support these use-cases, the load estimators in this module are parameterized by the
26//! [`TrackCompletion`] trait, with [`CompleteOnResponse`] as the default type. The behavior of
27//! [`CompleteOnResponse`] is what you would normally expect for a request-response cycle: when the
28//! response is produced, the request is considered "finished", and load goes down. This can be
29//! overriden by your own user-defined type to track more complex request completion semantics. See
30//! the documentation for [`completion`] for more details.
31//!
32//! # Examples
33//!
34//! ```rust
35//! # #[cfg(feature = "util")]
36//! use tower::util::ServiceExt;
37//! # #[cfg(feature = "util")]
38//! use tower::{load::Load, Service};
39//! # #[cfg(feature = "util")]
40//! async fn simple_balance<S1, S2, R>(
41//! svc1: &mut S1,
42//! svc2: &mut S2,
43//! request: R
44//! ) -> Result<S1::Response, S1::Error>
45//! where
46//! S1: Load + Service<R>,
47//! S2: Load<Metric = S1::Metric> + Service<R, Response = S1::Response, Error = S1::Error>
48//! {
49//! if svc1.load() < svc2.load() {
50//! svc1.ready().await?.call(request).await
51//! } else {
52//! svc2.ready().await?.call(request).await
53//! }
54//! }
55//! ```
56//!
57//! [`tower::balance`]: crate::balance
58//! [`Discover`]: crate::discover::Discover
59//! [`CompleteOnResponse`]: crate::load::completion::CompleteOnResponse
60// TODO: a custom completion example would be good here
61
62pub mod completion;
63mod constant;
64pub mod peak_ewma;
65pub mod pending_requests;
66
67pub use self::{
68 completion::{CompleteOnResponse, TrackCompletion},
69 constant::Constant,
70 peak_ewma::PeakEwma,
71 pending_requests::PendingRequests,
72};
73
74#[cfg(feature = "discover")]
75pub use self::{peak_ewma::PeakEwmaDiscover, pending_requests::PendingRequestsDiscover};
76
77/// Types that implement this trait can give an estimate of how loaded they are.
78///
79/// See the module documentation for more details.
80pub trait Load {
81 /// A comparable load metric.
82 ///
83 /// Lesser values indicate that the service is less loaded, and should be preferred for new
84 /// requests over another service with a higher value.
85 type Metric: PartialOrd;
86
87 /// Estimate the service's current load.
88 fn load(&self) -> Self::Metric;
89}