View Source Hammer.Atomic.LeakyBucket (hammer v7.0.0-rc.3)

This module implements the Leaky Bucket algorithm.

The leaky bucket algorithm works by modeling a bucket that:

  • Fills up with requests at the input rate
  • "Leaks" requests at a constant rate
  • Has a maximum capacity (the bucket size)

For example, with a leak rate of 10 requests/second and bucket size of 100:

  • Requests add to the bucket's current level
  • The bucket leaks 10 requests per second steadily
  • If bucket reaches capacity (100), new requests are denied
  • Once bucket level drops, new requests are allowed again

The algorithm:

  1. When a request comes in, we:
    • Calculate how much has leaked since last request
    • Subtract leaked amount from current bucket level
    • Try to add new request to bucket
    • Store new bucket level and timestamp
  2. To check if rate limit is exceeded:
    • If new bucket level <= capacity: allow request
    • If new bucket level > capacity: deny and return time until enough leaks
  3. Old entries are automatically cleaned up after expiration

This provides smooth rate limiting with ability to handle bursts up to bucket size. The leaky bucket is a good choice when:

  • You need to enforce a constant processing rate
  • Want to allow temporary bursts within bucket capacity
  • Need to smooth out traffic spikes
  • Want to prevent resource exhaustion

Common use cases include:

  • API rate limiting needing consistent throughput
  • Network traffic shaping
  • Service protection from sudden load spikes
  • Queue processing rate control
  • Scenarios needing both burst tolerance and steady-state limits

The main advantages are:

  • Smooth, predictable output rate
  • Configurable burst tolerance
  • Natural queueing behavior

The tradeoffs are:

  • More complex implementation than fixed windows
  • Need to track last request time and current bucket level
  • May need tuning of bucket size and leak rate parameters

For example, with 100 requests/sec limit and 500 bucket size:

  • Can handle bursts of up to 500 requests
  • But long-term average rate won't exceed 100/sec
  • Provides smoother traffic than fixed windows

The leaky bucket algorithm supports the following options:

  • :clean_period - How often to run the cleanup process (in milliseconds) Defaults to 1 minute. The cleanup process removes expired bucket entries.

  • :key_older_than - Optional maximum age for bucket entries (in milliseconds) If set, entries older than this will be removed during cleanup. This helps prevent memory growth from abandoned buckets.

Example configuration:

MyApp.RateLimit.start_link(
  clean_period: :timer.minutes(5),
  key_older_than: :timer.hours(24)
)

This would run cleanup every 5 minutes and remove buckets not used in 24 hours.

Summary

Functions

Returns the current level of the bucket for a given key.

Checks if a key is allowed to perform an action, and increment the counter by the given amount.

Functions

@spec get(table :: atom(), key :: String.t()) :: non_neg_integer()

Returns the current level of the bucket for a given key.

Link to this function

hit(table, key, leak_rate, capacity, cost)

View Source
@spec hit(
  table :: atom(),
  key :: String.t(),
  leak_rate :: pos_integer(),
  capacity :: pos_integer(),
  cost :: pos_integer()
) :: {:allow, non_neg_integer()} | {:deny, non_neg_integer()}

Checks if a key is allowed to perform an action, and increment the counter by the given amount.