Skip to main content
Version: Next (unreleased)

Leaky Bucket

A bucket of size capacity drains ("leaks") at rate units per second. Each request pours one unit in (or n for AllowN). A request that would overflow the bucket is denied.

// Drains 10 per second, holds up to 50
limiter := ratelimit.NewLeakyBucket(10, 50)

// The same rate, written per duration
limiter = ratelimit.NewLeakyBucketPerDuration(600, time.Minute, 50)

The bucket starts empty, so the first capacity requests are accepted at once.

:::note A meter, not a queue

This is the leaky bucket as a meter. Denied requests are rejected immediately; nothing is queued and nothing is delayed. If you want a caller to wait for room, use Wait, which blocks until the request fits.

:::

Relation to the token bucket​

Measured from the other side, the water level of a leaky bucket is the number of tokens a token bucket is missing. With the same rate and size, the two make identical decisions; the differences are presentational:

Token bucketLeaky bucket
Countstokens availablewater used
Startsfull of tokensempty of water
Size argumentburstcapacity
Inspect withTokens()Water()
Redis implementation✓—

Choose whichever models your problem more naturally. If you might move to Redis later, choose the token bucket.

Result fields​

FieldValue
Limitcapacity
Remainingroom left in the bucket after the decision
RetryAfterwhen denied, the time until enough has drained
ResetAtalways zero

Inspecting the bucket​

limiter.Water() // float64 — current level, after draining
limiter.Rate() // drain rate per second
limiter.Capacity() // size

Per-key​

limiter := ratelimit.NewKeyedLeakyBucket(10, 50, time.Minute)
defer limiter.Close()

limiter.Allow("user:42")

NewKeyedLeakyBucketPerDuration(count, per, capacity, cleanupInterval) is also available. See Keyed Limiters.