pub struct RedisRateLimiter { /* private fields */ }Expand description
A distributed, fixed-window rate limiter backed by a Redis server.
RateLimiter only protects a single process: two rws instances behind
a load balancer each track their own in-memory counters, so the effective
limit for a client doubles (or worse) as replicas scale out. RedisRateLimiter
keys the counter on a shared Redis server instead, so every instance enforces
the same budget.
Unlike RateLimiter’s sliding window (a deque of timestamps), this uses a
fixed-window counter: key’s count lives under one Redis key with a TTL equal
to the window length, incremented atomically via INCR. This is the standard
distributed rate-limiting pattern — Redis guarantees INCR is atomic across
concurrent callers, so counters stay correct even under heavy concurrent load
from multiple rws processes. The tradeoff versus a sliding window: a client
can burst up to 2x max_requests across a window boundary (once near the end
of one window, once at the start of the next).
Cloning is cheap — all clones share the same underlying TCP connection (one
persistent connection per RedisRateLimiter instance).
§Example
use rust_web_server::rate_limit::RedisRateLimiter;
let limiter = RedisRateLimiter::new("127.0.0.1:6379", None, 100, 60); // 100 req / 60s
match limiter.check("192.168.1.1") {
Ok(true) => { /* process request */ }
Ok(false) => { /* return 429 Too Many Requests */ }
Err(e) => { /* Redis unreachable — decide fail-open vs fail-closed */ }
}Implementations§
Source§impl RedisRateLimiter
impl RedisRateLimiter
Sourcepub fn new(
addr: impl Into<String>,
password: Option<String>,
max_requests: u32,
window_secs: u64,
) -> Self
pub fn new( addr: impl Into<String>, password: Option<String>, max_requests: u32, window_secs: u64, ) -> Self
Create a limiter that connects to addr (e.g. "127.0.0.1:6379"),
allowing max_requests per window_secs-second window.
password is passed to Redis AUTH if Some.
Sourcepub fn from_env() -> Self
pub fn from_env() -> Self
Build a limiter from environment variables:
RWS_REDIS_HOST(default127.0.0.1)RWS_REDIS_PORT(default6379)RWS_REDIS_PASSWORD(optional)RWS_CONFIG_RATE_LIMIT_MAX_REQUESTS(default1000)RWS_CONFIG_RATE_LIMIT_WINDOW_SECS(default60)
Sourcepub fn set_limits(&self, max_requests: u32, window_secs: u64)
pub fn set_limits(&self, max_requests: u32, window_secs: u64)
Update the limits on a live limiter without restarting.
Sourcepub fn check(&self, key: &str) -> Result<bool>
pub fn check(&self, key: &str) -> Result<bool>
Returns Ok(true) if key (typically a client IP) is within the rate
limit, Ok(false) if the limit has been exceeded, or Err if the
Redis server could not be reached.
A call always increments the shared counter, whether permitted or not,
so callers must decide for themselves whether to fail open (allow the
request) or fail closed (deny it) on Err — this limiter does not
silently pick one.