AAI Agentic Handbook
Problem 69 · Object & System Design

Rate Limiter: Token Bucket and Sliding-Window Log

MediumClassic DSA & systems
01Problem

Implement two per-client rate limiters with allow(client_id) -> bool: a token bucket (capacity, refill rate per second) and a sliding-window log (max N requests in any trailing W seconds). Clock must be injectable.

02Key insight

Token bucket stores just (tokens, last_refill) and refills lazily on each call, allowing bursts up to capacity. Sliding-window log is exact but O(N) memory per client; a deque lets you evict expired timestamps from the left in amortized O(1).

03Solution

Try it first.

TimeO(1) bucket; amortized O(1) log
SpaceO(clients) bucket; O(clients * limit) log
tests.py · 4 passing
tests.pypython11 lines
clock = [0.0]
tb = TokenBucketLimiter(capacity=2, refill_per_sec=1, now=lambda: clock[0])
assert [tb.allow("a") for _ in range(3)] == [True, True, False]
assert tb.allow("b")                  # independent client
clock[0] = 1.0
assert tb.allow("a") and not tb.allow("a")
clock[0] = 0.0
sw = SlidingWindowLogLimiter(limit=2, window_sec=10, now=lambda: clock[0])
assert sw.allow("a") and sw.allow("a") and not sw.allow("a")
clock[0] = 9.9; assert not sw.allow("a")
clock[0] = 10.0; assert sw.allow("a")
04Staff-level follow-up

Distributed across many API servers? Keep state in Redis with an atomic Lua script per check (or GCRA), accept slight over-admission via local pre-allocation of tokens to cut round trips.