~/Token Bucket Rate Limiting in Go

Aug 8, 2025


The golang.org/x/time/rate package implements rate limiting using the token bucket algorithm, which is foundational in network traffic shaping and distributed system design. The rate package provides types and methods for configuring advanced throttling with burst handling, efficient multi-request admission, context-aware blocking, and fine-grained dynamic configuration. The package is actively used by major projects and is imported by over 12000 repositories.

Package Structure

The main exported types are Limiter, Limit, Reservation and Sometimes. The package uses time.Duration as well as context.Context for context-sensitive waits.

Practical Usage and Observations

Creation of a limiter uses NewLimiter(). The zero value is a brick wall: it blocks every request.

A typical rate limit instantiation caps requests at 100 per second, with a burst of 10:

1
lim := rate.NewLimiter(rate.Limit(100), 10)

Most high concurrency codepaths use Allow() or Wait(), which either admit instantly or force suspension until a token is available. The token bucket model is conceptually elegant: calls accumulate or deplete tokens, bursts allow short-term overruns, and leaks refill at the desired rate. Google ironically popularized the algorithm in their infrastructure, explaining token buckets are like tiny bureaucrats checking paper slips.

Reserve() and ReserveN() allow token borrow-with-wait patterns. This supports fairness where dropping events is not an option. SetBurst() and SetLimit() allow runtime adaptation which some platforms abuse by trying to dynamically tune load shedding thresholds with dubious economic reasoning.

There is also support for infinite rate, which can be misused as an expensive bypass switch.

The WaitN() mechanism uses context.Context, which enables deadline-sensitive waits and cooperative cancellation. Heavily loaded systems should measure tail latencies, since excessive WaitN calls can add pathological latency if not bounded. In highly distributed workflows, use deadline-aware context hierarchies to avoid system deadlocks. See the Go context best practices for further nuance.

Satirical Features

Sometimes operates as a probabilistic sabotage for logging or notification spam, letting you run noisy routines First N times, or with specified periodicity. It is a solution for developers who want to avoid looking like this XKCD comic in production.

Code Examples

For API call admission, if silent dropping is acceptable, use:

1
2
3
if !lim.Allow() {
    // drop request
}

For mandatory processing, call:

1
2
3
4
err := lim.Wait(ctx)
if err != nil {
    // cancelled, context deadline or quota excess
}

For best-effort bulk processing:

1
2
3
if lim.AllowN(time.Now(), batchSize) {
    // proceed with batch
}

Integration in System Design

Historical Context

Trivia

Links for Further Exploration

Tags: [golang] [concurrency] [design] [goroutines]