Trait governor::middleware::RateLimitingMiddleware
source · pub trait RateLimitingMiddleware<P: Reference>: Debug {
type PositiveOutcome: Sized;
type NegativeOutcome: Sized;
// Required methods
fn allow<K>(
key: &K,
state: impl Into<StateSnapshot>,
) -> Self::PositiveOutcome;
fn disallow<K>(
key: &K,
limiter: impl Into<StateSnapshot>,
start_time: P,
) -> Self::NegativeOutcome;
}
Expand description
Defines the behavior and return values of rate limiting decisions.
While the rate limiter defines whether a decision is positive, the
middleware defines what additional values (other than Ok
or Err
)
are returned from the RateLimiter
’s check methods.
The default middleware in this crate is NoOpMiddleware
(which does
nothing in the positive case and returns NotUntil
in the
negative) - so it does only the smallest amount of work it needs to do
in order to be useful to users.
Other middleware gets to adjust these trade-offs: The pre-made
StateInformationMiddleware
returns quota and burst capacity
information, while custom middleware could return a set of HTTP
headers or increment counters per each rate limiter key’s decision.
§Defining your own middleware
Here’s an example of a rate limiting middleware that does no computations at all on positive and negative outcomes: All the information that a caller will receive is that a request should be allowed or disallowed. This can allow for faster negative outcome handling, and is useful if you don’t need to tell users when they can try again (or anything at all about their rate limiting status).
use governor::{middleware::{RateLimitingMiddleware, StateSnapshot},
Quota, RateLimiter, clock::Reference};
#[derive(Debug)]
struct NullMiddleware;
impl<P: Reference> RateLimitingMiddleware<P> for NullMiddleware {
type PositiveOutcome = ();
type NegativeOutcome = ();
fn allow<K>(_key: &K, _state: impl Into<StateSnapshot>) -> Self::PositiveOutcome {}
fn disallow<K>(_: &K, _: impl Into<StateSnapshot>, _: P) -> Self::NegativeOutcome {}
}
let lim = RateLimiter::direct(Quota::per_hour(nonzero!(1_u32)))
.with_middleware::<NullMiddleware>();
assert_eq!(lim.check(), Ok(()));
assert_eq!(lim.check(), Err(()));
Required Associated Types§
sourcetype PositiveOutcome: Sized
type PositiveOutcome: Sized
The type that’s returned by the rate limiter when a cell is allowed.
By default, rate limiters return Ok(())
, which does not give
much information. By using custom middleware, users can obtain
more information about the rate limiter state that was used to
come to a decision. That state can then be used to pass
information downstream about, e.g. how much burst capacity is
remaining.
sourcetype NegativeOutcome: Sized
type NegativeOutcome: Sized
The type that’s returned by the rate limiter when a cell is not allowed.
By default, rate limiters return Err(NotUntil)
, which
allows interrogating the minimum amount of time to wait until
a client can expect to have a cell allowed again.
Required Methods§
sourcefn allow<K>(key: &K, state: impl Into<StateSnapshot>) -> Self::PositiveOutcome
fn allow<K>(key: &K, state: impl Into<StateSnapshot>) -> Self::PositiveOutcome
Called when a positive rate-limiting decision is made.
This function is able to affect the return type of RateLimiter.check (and others) in the Ok case: Whatever is returned here is the value of the Ok result returned from the check functions.
The function is passed a snapshot of the rate-limiting state
updated to after the decision was reached: E.g., if there
was one cell left in the burst capacity before the decision
was reached, the StateSnapshot::remaining_burst_capacity
method will return 0.
sourcefn disallow<K>(
key: &K,
limiter: impl Into<StateSnapshot>,
start_time: P,
) -> Self::NegativeOutcome
fn disallow<K>( key: &K, limiter: impl Into<StateSnapshot>, start_time: P, ) -> Self::NegativeOutcome
Called when a negative rate-limiting decision is made (the “not allowed but OK” case).
This method returns whatever value is returned inside the
Err
variant a RateLimiter
’s check
method returns.