CODING CHALLENGE · N°22

Token Bucket Rate Limiter

Medium SystemsRate LimitingDistributed Systems

The algorithm inside most production rate limiters — and it never runs a timer. A bucket refills lazily: on each request, credit the time elapsed since the last one, cap at capacity, spend one token or reject. Two numbers of state per client.

The problem

Implement a token bucket as a pure replay: given capacity (max tokens), rate (tokens refilled per second), and times — a non-decreasing list of request timestamps in seconds — return a list of booleans, one per request: accepted or rejected. The bucket starts full. Refill lazily: at each request, add (t − t_last) · rate tokens (capped at capacity, where t_last is the previous request time), then accept if at least 1 token remains (spend it) or reject (spend nothing).

EXAMPLE 1
Input capacity = 2, rate = 1, times = [0, 0, 0, 1, 3]
Output [true, true, false, true, true]
burst of 2 passes, third rejected, refill revives later requests
EXAMPLE 2
Input capacity = 5, rate = 1, times = [0,1,2,3,4]
Output all true
request rate ≤ refill rate never rejects
EXAMPLE 3
Input capacity = 1, rate = 0.5, times = [0, 1, 2]
Output [true, false, true]
fractional refill: 1 token back after 2 seconds
CONSTRAINTS
  • The bucket starts full (tokens = capacity).
  • Refill is lazy and fractional — no timers, no rounding.
  • Rejected requests spend nothing (tokens unchanged apart from the refill).
  • times is non-decreasing; equal timestamps are legal (a burst).
SOLVE IT YOURSELF

Your turn — write it

Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.

YOUR TASK

Implement token_bucket(capacity, rate, times) → list of accept/reject booleans, using lazy fractional refill from a bucket that starts full.

HINTS — 4 IDEAS
  1. Keep two state variables: current tokens and the previous request timestamp.
  2. On each request: tokens = min(capacity, tokens + (t − t_last) · rate), then t_last = t.
  3. Accept iff tokens ≥ 1; subtract 1 only on accept.
  4. This is exactly what production limiters store per key in Redis — two numbers, no timer.
CPython · WebAssembly

Explore the topic

See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.