pub struct RateLimitEngine { /* private fields */ }Expand description
Policy-resolution and key-building engine for request rate limiting (DW-017). Compiled once per config generation.
Precedence chain (frozen vocabulary: consumer, then route, then
service, then listener, then global): rules from ALL applicable
policies apply and are AND-ed; the resolution order is consumer
(authenticated requests carry their consumer’s policies), then route,
then service, then listener (listeners[].policies, the listener
that accepted the request), then global (gateway.global_policies).
The order matters for the 429 HEADERS only (the first denying rule
binds Limit/Remaining/Reset; see RateLimitEngine::check); every
applicable rule still gates the request. On UNROUTED traffic
(no route resolved) only the listener and global links apply —
consumer, route, and service links are unknowable before routing,
and the documented request-path order places authentication after
route resolution.
Key building per rule: each selector contributes one component
(ip = peer, credential = consumer or peer fallback, route =
route name; the empty string for unrouted requests); components are
joined with | into one key. Rules attached to the same policy
share a limiter instance, so two rules with identical selectors and
windows would double-count — validation does not reject it
(harmless), operators just should not write it.
Implementations§
Source§impl RateLimitEngine
impl RateLimitEngine
Sourcepub fn compile(gateway: &Gateway) -> Self
pub fn compile(gateway: &Gateway) -> Self
Compile every policy’s rate rules of a config generation. Policies without rate rules contribute nothing (their timeouts and future plugin bundles are other layers’ concern).
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Whether any rule is compiled in at all (fast path: configs with no rate-limit policies skip per-request key building entirely).
Sourcepub fn live_keys(&self) -> usize
pub fn live_keys(&self) -> usize
Live per-key cell count across every compiled rule’s windows
(approximate under concurrent checks) — the spray-bounded figure
for tests and ops visibility. See GcraRateLimiter::live_keys.
Sourcepub fn evictions(&self) -> u64
pub fn evictions(&self) -> u64
Cells dropped by eviction sweeps across every compiled rule
(monotonic per config generation). See GcraRateLimiter::evictions.
Sourcepub async fn check(
&self,
ctx: &RateLimitKeyContext<'_>,
consumer_policies: &[String],
route_policies: &[String],
service_policies: &[String],
listener_policies: &[String],
global_policies: &[String],
) -> RateLimitOutcome
pub async fn check( &self, ctx: &RateLimitKeyContext<'_>, consumer_policies: &[String], route_policies: &[String], service_policies: &[String], listener_policies: &[String], global_policies: &[String], ) -> RateLimitOutcome
Resolve the applicable rules for one request and check them.
The policy name lists are those attached to the authenticated
consumer (DW-019; empty for anonymous traffic), the matched
route, its service, the accepting listener, and the gateway
(global) — in that resolution order (the frozen precedence
chain). On unrouted traffic the caller passes empty
consumer/route/service lists (ctx.route is then the empty
string) and only the listener/global links resolve.
A policy attached at multiple levels (or repeated within one
list) is evaluated ONCE per request; its first — most
specific — chain position is the occurrence that binds the
429 headers.
All applicable rules apply (AND); on success the reported
constraint is the tightest one (least remaining budget). On denial
the FIRST denying rule binds the Limit/Remaining/Reset headers,
but evaluation continues through the remaining applicable rules so
retry_after_s (and the matching Reset) reflect the MAXIMUM wait
any denying rule demands — a client honoring the hint never
retries into a second 429 with an understated Retry-After.
Dry-run bundles (DW-041, policies[].dry_run) never contribute
to this outcome — see RateLimitEngine::evaluate, which this
delegates to.
Sourcepub async fn evaluate<F>(
&self,
ctx: &RateLimitKeyContext<'_>,
consumer_policies: &[String],
route_policies: &[String],
service_policies: &[String],
listener_policies: &[String],
global_policies: &[String],
adaptive_factor: F,
) -> RateLimitEvaluation
pub async fn evaluate<F>( &self, ctx: &RateLimitKeyContext<'_>, consumer_policies: &[String], route_policies: &[String], service_policies: &[String], listener_policies: &[String], global_policies: &[String], adaptive_factor: F, ) -> RateLimitEvaluation
Self::check with the dry-run observation attached (DW-041):
every applicable rule still EVALUATES (dry bundles’ GCRA buckets
advance exactly as if enforcing, so their denial rates reflect
what enforcement would do), but the enforcement outcome is
computed from LIVE rules only, while dry_denied carries the
first (most specific) dry bundle’s would-be denial for the caller
to log and count. Dry bundles also contribute no
X-RateLimit-* header values: a monitor never touches the
response. A request can therefore be BOTH 429’d by a live rule
and reported as a dry would-deny in the same evaluation.
adaptive_factor (DW-089) maps a policy name to its current
adaptive factor (1.0 = no tuning). The factor scales the
per-request COST against the GCRA bucket: a factor < 1.0
(tightened) increases the cost so the effective rate drops; a
factor > 1.0 (relaxed) decreases the cost so the effective rate
rises. The limiter is NOT rebuilt — the factor is applied at
check time. Extensions may not import resilience, so the caller
(the dataplane) supplies the factor lookup.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for RateLimitEngine
impl RefUnwindSafe for RateLimitEngine
impl Send for RateLimitEngine
impl Sync for RateLimitEngine
impl Unpin for RateLimitEngine
impl UnwindSafe for RateLimitEngine
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more