php 46 lines · 7 steps

How a token bucket rate limiter works

A token bucket smooths request bursts by refilling credits over time and blocking callers until enough tokens are available.

Explained by highlit
1final class TokenBucketLimiter
2{
3 private float $tokens;
4 private float $lastRefill;
5 
6 public function __construct(
7 private readonly float $capacity,
8 private readonly float $refillPerSecond
9 ) {
10 $this->tokens = $capacity;
11 $this->lastRefill = microtime(true);
12 }
13 
14 public function acquire(float $cost = 1.0): void
15 {
16 if ($cost > $this->capacity) {
17 throw new InvalidArgumentException('Cost exceeds bucket capacity');
18 }
19 
20 while (true) {
21 $this->refill();
22 
23 if ($this->tokens >= $cost) {
24 $this->tokens -= $cost;
25 return;
26 }
27 
28 $deficit = $cost - $this->tokens;
29 $waitSeconds = $deficit / $this->refillPerSecond;
30 usleep((int) ceil($waitSeconds * 1_000_000));
31 }
32 }
33 
34 private function refill(): void
35 {
36 $now = microtime(true);
37 $elapsed = $now - $this->lastRefill;
38 
39 if ($elapsed <= 0) {
40 return;
41 }
42 
43 $this->tokens = min($this->capacity, $this->tokens + $elapsed * $this->refillPerSecond);
44 $this->lastRefill = $now;
45 }
46}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A token bucket allows short bursts up to capacity while enforcing a steady average rate over time.
  2. 2Refilling lazily from elapsed time avoids running a background timer to add tokens.
  3. 3Computing the wait from the exact token deficit lets a blocked caller sleep just long enough instead of busy-polling.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a token bucket rate limiter works — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code