pub struct Layered<K, E = K>{ /* private fields */ }std only.Expand description
Several scopes of limiting stacked so a request must clear every one.
A real service limits at more than one granularity at once: an overall
ceiling for the whole process (the global scope), a fair share per caller
(the per-key scope, keyed by tenant or token), and a ceiling per route (the
per-endpoint scope). Layered checks the scopes that are configured and
admits a request only when all of them can afford it — applied atomically by
the same peek-then-commit rule the other composites use, so a request never
spends in one scope when another blocks it.
The two key types are independent: a numeric tenant id and a string endpoint, say. They default to the same type for the common all-string case.
Build one with Layered::builder. Every scope is optional; a builder with
none admits everything.
§Examples
use throttle_net::{Layered, PerKey, Throttle};
// 1000/s overall, 100/s per tenant, 50/s per endpoint.
let layered = Layered::<String>::builder()
.global(Throttle::per_second(1000))
.per_key(PerKey::per_second(100))
.per_endpoint(PerKey::per_second(50))
.build();
layered
.acquire(&"tenant:42".to_string(), &"/v1/chat".to_string())
.await?;Implementations§
Source§impl<K, E> Layered<K, E>
impl<K, E> Layered<K, E>
Sourcepub fn builder() -> LayeredBuilder<K, E>
pub fn builder() -> LayeredBuilder<K, E>
Starts building a layered limiter.
Sourcepub fn capacity(&self) -> u32
pub fn capacity(&self) -> u32
The binding capacity across configured scopes: the smallest, since that is
the first ceiling a request hits. No scopes means unbounded (u32::MAX).
Sourcepub fn try_acquire(&self, key: &K, endpoint: &E) -> bool
pub fn try_acquire(&self, key: &K, endpoint: &E) -> bool
Attempts to admit one request for (key, endpoint) without waiting.
§Examples
use throttle_net::{Layered, PerKey, Throttle};
let layered = Layered::<&str>::builder()
.global(Throttle::per_second(2))
.per_key(PerKey::per_second(1))
.build();
assert!(layered.try_acquire(&"a", &"/x"));
// The per-key scope for "a" is now empty, even though the global has room.
assert!(!layered.try_acquire(&"a", &"/x"));
assert!(layered.try_acquire(&"b", &"/x")); // a different key is independentSource§impl<K, E> Layered<K, E>
impl<K, E> Layered<K, E>
Sourcepub async fn acquire(&self, key: &K, endpoint: &E) -> Result<(), ThrottleError>
Available on crate feature runtime only.
pub async fn acquire(&self, key: &K, endpoint: &E) -> Result<(), ThrottleError>
runtime only.Admits one request for (key, endpoint), waiting until every scope can.
§Errors
Returns ThrottleError::CostExceedsCapacity if some scope’s capacity is
too small to ever admit the request.
Sourcepub async fn acquire_with_cost(
&self,
key: &K,
endpoint: &E,
cost: u32,
) -> Result<(), ThrottleError>
Available on crate feature runtime only.
pub async fn acquire_with_cost( &self, key: &K, endpoint: &E, cost: u32, ) -> Result<(), ThrottleError>
runtime only.Admits a request of weight cost for (key, endpoint), waiting until
every scope can.
§Errors
Returns ThrottleError::CostExceedsCapacity if some scope can never
admit cost.