Problem 84 · Concurrency & Python
Thread-Safe Token Bucket Rate Limiter
01Problem
Implement a token bucket with a refill rate and burst capacity that supports try_acquire(n) and reports how long to wait, safe under concurrent callers.
02Key insight
Refill lazily on each call from elapsed time instead of using a background timer; inject the clock for deterministic tests. Guard refill+consume with one lock so the check-then-act is atomic.
03Solution
Try it first.
TimeO(1) per call
SpaceO(1)
tests.py · 4 passing
tests.pypython16 lines
import threading
now = [0.0]
tb = TokenBucket(rate=2, capacity=5, clock=lambda: now[0])
assert sum(tb.try_acquire() for _ in range(10)) == 5
assert tb.wait_time(1) == 0.5
now[0] = 1.0
assert tb.try_acquire(2) and not tb.try_acquire()
# concurrency: frozen clock, 8 threads hammering -> exactly capacity succeed
tb2 = TokenBucket(rate=1, capacity=10, clock=lambda: 0.0)
wins = []
def worker():
wins.append(sum(tb2.try_acquire() for _ in range(100)))
ts = [threading.Thread(target=worker) for _ in range(8)]
for t in ts: t.start()
for t in ts: t.join()
assert sum(wins) == 1004Staff-level follow-up
How do you rate-limit across 50 API servers? Keep the bucket in Redis and do refill+consume atomically in a Lua script keyed by tenant; or give each node a local bucket with rate/N and periodically rebalance to avoid a hot central dependency.