RateLimitEngine

Struct RateLimitEngine 

Source
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

Source

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).

Source

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).

Source

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.

Source

pub fn evictions(&self) -> u64

Cells dropped by eviction sweeps across every compiled rule (monotonic per config generation). See GcraRateLimiter::evictions.

Source

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.

Source

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
where F: Fn(&str) -> f64,

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§

Source§

impl Debug for RateLimitEngine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> AnyExt for T
where T: Any + ?Sized,

§

fn downcast_ref<T>(this: &Self) -> Option<&T>
where T: Any,

Attempts to downcast this to T behind reference
§

fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>
where T: Any,

Attempts to downcast this to T behind mutable reference
§

fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>
where T: Any,

Attempts to downcast this to T behind Rc pointer
§

fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>
where T: Any,

Attempts to downcast this to T behind Arc pointer
§

fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>
where T: Any,

Attempts to downcast this to T behind Box pointer
§

fn downcast_move<T>(this: Self) -> Option<T>
where T: Any, Self: Sized,

Attempts to downcast owned Self to T, useful only in generic context as a workaround for specialization
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T, X> CoerceTo<T> for X
where 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

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> ServiceExt for T

§

fn map_response_body<F>(self, f: F) -> MapResponseBody<Self, F>
where Self: Sized,

Apply a transformation to the response body. Read more
§

fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using HTTP status codes. Read more
§

fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using gRPC headers. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,