ruby 48 lines · 8 steps

A thread-safe token bucket rate limiter in Ruby

A token bucket smooths bursts and enforces a steady rate, kept correct across threads with a monitor.

Explained by highlit
1require 'monitor'
2 
3class TokenBucket
4 include MonitorMixin
5 
6 def initialize(capacity:, refill_rate:)
7 super()
8 @capacity = capacity.to_f
9 @refill_rate = refill_rate.to_f
10 @tokens = @capacity
11 @last_refill = monotonic_now
12 end
13 
14 def allow?(cost = 1)
15 synchronize do
16 refill
17 if @tokens >= cost
18 @tokens -= cost
19 true
20 else
21 false
22 end
23 end
24 end
25 
26 def wait_time(cost = 1)
27 synchronize do
28 refill
29 return 0.0 if @tokens >= cost
30 (cost - @tokens) / @refill_rate
31 end
32 end
33 
34 private
35 
36 def refill
37 now = monotonic_now
38 elapsed = now - @last_refill
39 return if elapsed <= 0
40 
41 @tokens = [@capacity, @tokens + elapsed * @refill_rate].min
42 @last_refill = now
43 end
44 
45 def monotonic_now
46 Process.clock_gettime(Process::CLOCK_MONOTONIC)
47 end
48end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A token bucket permits short bursts up to its capacity while enforcing a long-run average rate.
  2. 2Lazy refill on each check avoids background timers by computing tokens from elapsed time.
  3. 3A monotonic clock keeps interval math immune to system clock adjustments.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A thread-safe token bucket rate limiter in Ruby — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code