The Leaky Bucket Pattern: Smoothing Bursty Traffic Into a Steady Stream

2026-07-04

Throttling caps the rate of accepted requests, but sometimes you want the opposite: accept whatever comes in, then release it downstream at a controlled, uniform pace. That's the leaky bucket. Imagine a bucket with a hole in the bottom — water pours in at whatever rate the world provides, but drips out at a fixed rate. If the bucket overflows, incoming water spills.

Two variants show up in practice, and confusing them causes bugs:

Real-world example. You run a payment service that calls a partner API capped at 10 requests/second. Your users submit refunds in bursts — 200 in a second when a batch job fires, then nothing for a minute. If you forward the burst, the partner returns 429s and you lose refunds. Wrap the partner call in a leaky bucket: incoming refunds enqueue into a buffer of, say, 500 slots. A worker drains the buffer at exactly 10 req/s. Your users see the refund "accepted" instantly; downstream stays under the ceiling; overflow (buffer full) is the only failure mode you have to handle.

Rule of thumb for sizing. Bucket size = burst tolerance × leak rate. If your leak rate is 10/s and you want to absorb a 30-second burst without dropping, size the bucket at 300. Bigger buckets absorb more burst but add latency — a request that arrives when the bucket is 250 deep waits 25 seconds before dispatch. Always cap bucket size so you fail fast rather than silently building up minutes of backlog.

Leaky bucket vs token bucket. Token bucket allows bursts up to the bucket size (tokens accumulate during idle periods). Leaky bucket forbids bursts downstream — output is always uniform. Pick leaky when the downstream system genuinely can't handle bursts (external API quotas, hardware with fixed throughput, fairness across tenants). Pick token when bursts are fine and you just want a long-run rate cap.

Common mistake. Using a leaky bucket in front of a synchronous request-response API. If callers block waiting for the leak, you've just moved the queue from downstream to your own connection pool. Leaky bucket wants an async boundary — accept the request, return a job ID, dispatch later.

See it in action: Check out I Sneaked Into Girls
#39; Dorm and Awakened a God-Tier Drunken System! #anime #dub by AnimeNexus Recap to see this theory applied.
Key Takeaway: Use a leaky bucket when the downstream system needs a steady drip, not when your callers need instant answers — it trades latency for uniformity.