pub struct RateLimiter { /* private fields */ }Expand description
The sliding-window rate limiter over one shared in-memory store.
Build it once at startup with RateLimiter::new (fail closed on a
non-positive limit or window) and share the handle across requests; the
internal store is a mutex-guarded LRU, safe for concurrent services.
Implementations§
Source§impl RateLimiter
impl RateLimiter
Sourcepub fn new(config: RateLimitConfig) -> Result<Self, RateLimitConfigError>
pub fn new(config: RateLimitConfig) -> Result<Self, RateLimitConfigError>
Validate the config and build the limiter.
§Errors
Fails closed with a RateLimitConfigError when rate_limit or
rate_limit_window is zero (the reference rejects both with
ge=1); nothing but RateLimitConfig::default-shaped values is
substituted silently.
Sourcepub fn with_config_and_clock(
config: RateLimitConfig,
clock: Clock,
) -> Result<Self, RateLimitConfigError>
pub fn with_config_and_clock( config: RateLimitConfig, clock: Clock, ) -> Result<Self, RateLimitConfigError>
Validate the config and build the limiter over an injected clock: the
combined seam new and with_clock
cover separately. Production builds use RateLimiter::new; adapters
and stage tests that drive window sliding with a fake clock under a
production-shaped config use this one.
§Errors
Same fail-closed behavior as RateLimiter::new: a zero rate_limit
or rate_limit_window is a RateLimitConfigError.
Sourcepub fn with_config(
&self,
config: RateLimitConfig,
) -> Result<Self, RateLimitConfigError>
pub fn with_config( &self, config: RateLimitConfig, ) -> Result<Self, RateLimitConfigError>
A limiter over config that shares this one’s window store, clock
and distributed store: the live-config swap a dynamic rule drives
(the limits change, the recorded windows stay).
§Errors
Same fail-closed validation as RateLimiter::new.
Sourcepub fn with_distributed_store(
self,
store: Arc<dyn SlidingWindowStore>,
redis_prefix: &str,
redis_fail_open: bool,
) -> Self
pub fn with_distributed_store( self, store: Arc<dyn SlidingWindowStore>, redis_prefix: &str, redis_fail_open: bool, ) -> Self
Swap the wall clock. Test seam: production builds use the system
clock; deterministic window-sliding coverage injects a fake.
Run the limiter over a distributed window store (the reference
enable_redis && redis_handler conjunction): every tier’s hit
records into {prefix}rate_limit:rate:{ip}[:{endpoint hash}]
through one transaction of the reference’s four operations, and
the decision compares the post-recording count with
count <= limit (the Redis formulation; the same boundary as the
in-memory count < limit).
redis_fail_open = true mirrors the reference redis_fail_open:
a failing backend call degrades to the in-memory window (the
workers x rate_limit caveat applies); false (the default)
surfaces the failure as Err so the caller can answer the
reference 503 "Redis rate limiting unavailable".
Sourcepub fn check_distributed(
&self,
ip: IpAddr,
endpoint: Option<&str>,
) -> Result<RateLimitDecision, StoreError>
pub fn check_distributed( &self, ip: IpAddr, endpoint: Option<&str>, ) -> Result<RateLimitDecision, StoreError>
RateLimiter::check over the distributed store: Err means a
failing backend with redis_fail_open = false.
§Errors
StoreError when the backend
call fails and fail-open is off.
Sourcepub fn check_tiers_distributed(
&self,
ip: IpAddr,
url_path: Option<&str>,
route: Option<&RouteRateLimits>,
country_of_ip: Option<&dyn Fn(IpAddr) -> Option<String>>,
) -> Result<TierDecision, StoreError>
pub fn check_tiers_distributed( &self, ip: IpAddr, url_path: Option<&str>, route: Option<&RouteRateLimits>, country_of_ip: Option<&dyn Fn(IpAddr) -> Option<String>>, ) -> Result<TierDecision, StoreError>
RateLimiter::check_tiers over the distributed store: every
tier keys its window the way the reference does (endpoint tiers
keyed with the hashed path segment, the global tier by IP alone).
§Errors
StoreError when a tier’s
backend call fails and fail-open is off.
pub fn with_clock(clock: Clock) -> Self
Sourcepub const fn config(&self) -> &RateLimitConfig
pub const fn config(&self) -> &RateLimitConfig
The validated config the limiter decides under.
Sourcepub fn check(&self, ip: IpAddr, endpoint: Option<&str>) -> RateLimitDecision
pub fn check(&self, ip: IpAddr, endpoint: Option<&str>) -> RateLimitDecision
Record one request for ip and decide it.
endpoint selects the scope: None is the global per-IP window,
Some(path) the per-endpoint window keyed by (ip, path). A
disabled limiter allows without recording. The returned decision’s
count includes the request just recorded, so a block reports the
crossing count exactly as the references log it.
Sourcepub fn check_tiers(
&self,
ip: IpAddr,
url_path: Option<&str>,
route: Option<&RouteRateLimits>,
country_of_ip: Option<&dyn Fn(IpAddr) -> Option<String>>,
) -> TierDecision
pub fn check_tiers( &self, ip: IpAddr, url_path: Option<&str>, route: Option<&RouteRateLimits>, country_of_ip: Option<&dyn Fn(IpAddr) -> Option<String>>, ) -> TierDecision
Record one request for ip under every configured tier and decide
it (the reference RateLimitCheck.check order, via the Go port’s
tiersFor/runTier): the endpoint tier, the route tier, the geo
tier, then the global tier. Every configured tier records one hit
into its own window (each tier is an independent budget, exactly as
the references count), and the first tier that crosses its limit
decides the outcome with its own window for Retry-After.
url_path is the request path the endpoint tier matches
(endpoint_rate_limits exact match) and the route/geo tiers key
their windows by; without a path those tiers cannot key an isolated
window and are skipped (the references always carry a request path
here). route carries the decorator tiers (None skips both).
country_of_ip resolves the geolocation the geo tier reads (the
reference geo_handler.get_country); None or an unresolved
country skips the geo tier unless a "*" entry covers it. A
disabled limiter allows without recording anything.
Sourcepub fn reset(&self)
pub fn reset(&self)
Drop every window, every recorded request included (reset in the
references; test harnesses use it to isolate cases).
Sourcepub fn tracked_windows(&self) -> usize
pub fn tracked_windows(&self) -> usize
How many windows the store currently tracks (test/observability seam for the LRU cap).
Trait Implementations§
Source§impl Clone for RateLimiter
impl Clone for RateLimiter
Source§fn clone(&self) -> Self
fn clone(&self) -> Self
A clone shares the window store and the clock, the references’ singleton semantics: requests recorded through any handle land in the same sliding windows.
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more