Immutable token bucket rate limiter in Elixir
Elixir
defmodule TokenBucket do
@default_rate 5.0
@default_burst 5
def new(rate \\ @default_rate, burst \\ @default_burst) do
%{rate: rate, burst: burst, tokens: burst * 1.0, at: System.monotonic_time(:millisecond)}
end
def take(bucket, count \\ 1) do
now = System.monotonic_time(:millisecond)
elapsed = max(now - bucket.at, 0) / 1000
tokens = min(bucket.burst * 1.0, bucket.tokens + elapsed * bucket.rate)
if tokens >= count do
{:ok, %{bucket | tokens: tokens - count, at: now}}
else
{:error, tokens, %{bucket | tokens: tokens, at: now}}
end
end
end