High-throughput, concurrent sliding window counter rate limiter for Rust.
Zero dependencies. Pure sync core. True zero-allocation hot path. Deterministic testing via mock clock.
- Sliding window counter — weighted previous/current window, eliminates boundary bursts
- True zero-allocation hot path —
get_muton existing keys, no heap traffic - Exact
retry_after— mathematically precise intra- and inter-window decay - HashDoS resistant — SipHash-1-3 via stdlib
RandomStateby default - Saturating time arithmetic — clock skew and NTP step safe
- Accurate idle eviction — tracks precise
last_seenper key - Cost-aware admission — consume N units per check
- Sharded concurrency — parallel key access, no cross-shard contention
- Deterministic testing — mock clock without thread sleeping
- Zero dependencies — pure stdlib, no async runtime required
[dependencies]
ramgate = "0.2"use ramgate::RateLimiter;
use std::time::Duration;
// 100 requests per 60-second window, 16 shards
let limiter = RateLimiter::new(100, Duration::from_secs(60));
assert!(limiter.allow("ip:127.0.0.1"));
assert!(limiter.allow("ip:127.0.0.1"));
// Cost-aware: consume 5 units at once
let result = limiter.check_n("ip:10.0.0.1", 5);
assert!(result.is_ok());use ramgate::{RateLimiter, FakeClock};
use std::time::Duration;
let clock = FakeClock::new();
let limiter = RateLimiter::with_clock(5, Duration::from_secs(10), clock.clone());
for _ in 0..5 {
assert!(limiter.allow("key"));
}
assert!(!limiter.allow("key"));
// Advance past window boundary, then into new window
clock.advance(Duration::from_secs(10)); // rotation: previous=5, current=0
clock.advance(Duration::from_secs(5)); // previous_weight=0.5, weighted=2.5
assert!(limiter.allow("key")); // 2.5+1=3.5 <= 5Use FnvBuilder for high-throughput trusted environments (not HashDoS-safe):
use ramgate::{RateLimiter, FnvBuilder};
use std::time::Duration;
let limiter = RateLimiter::with_hasher(
100,
Duration::from_secs(60),
16,
ramgate::WallClock,
FnvBuilder,
);Sliding window counter: two fixed windows (current + previous), weighted sum. No boundary bursts. O(1) per check. O(1) amortized eviction.
| Property | Value |
|---|---|
| Check | O(1) |
| Memory per key | 32 bytes (2 u64 + 2 Instant) + key allocation |
| Shard count | Power of 2 (default: 16) |
| Default hasher | SipHash-1-3 (HashDoS resistant) |
| Dependencies | Zero |
MIT OR Apache-2.0