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

This module implements the Fix Window algorithm.

The fixed window algorithm works by dividing time into fixed intervals or "windows" of a specified duration (scale). Each window tracks request counts independently.

For example, with a 60 second window:

  • Window 1: 0-60 seconds
  • Window 2: 60-120 seconds
  • And so on...

The algorithm:

  1. When a request comes in, we:
    • Calculate which window it belongs to based on current time
    • Increment the counter for that window
    • Store expiration time as end of window
  2. To check if rate limit is exceeded:
    • If count <= limit: allow request
    • If count > limit: deny and return time until window expires
  3. Old windows are automatically cleaned up after expiration

This provides simple rate limiting but has edge cases where a burst of requests spanning a window boundary could allow up to 2x the limit in a short period. For more precise limiting, consider using the sliding window algorithm instead.

The fixed window algorithm is a good choice when:

  • You need simple, predictable rate limiting with clear time boundaries
  • The exact precision of the rate limit is not critical
  • You want efficient implementation with minimal storage overhead
  • Your use case can tolerate potential bursts at window boundaries

Common use cases include:

  • Basic API rate limiting where occasional bursts are acceptable
  • Protecting backend services from excessive load
  • Implementing fair usage policies
  • Scenarios where clear time-based quotas are desired (e.g. "100 requests per minute")

The main tradeoff is that requests near window boundaries can allow up to 2x the intended limit in a short period. For example with a limit of 100 per minute:

  • 100 requests at 11:59:59
  • Another 100 requests at 12:00:01

This results in 200 requests in 2 seconds, while still being within limits. If this behavior is problematic, consider using the sliding window algorithm instead.

The fixed window 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 window entries.

Example configuration:

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

This would run cleanup every 5 minutes and clean up old windows.

Summary

Functions

Returns the count of requests for a given key within the last <scale> seconds.

Checks if a key is allowed to perform an action based on the fixed window algorithm.

Increments the counter for a given key in the fixed window algorithm.

Sets the counter for a given key in the fixed window algorithm.

Functions

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

Returns the count of requests for a given key within the last <scale> seconds.

Link to this function

hit(table, key, scale, limit, increment)

View Source
@spec hit(
  table :: atom(),
  key :: String.t(),
  scale :: pos_integer(),
  limit :: pos_integer(),
  increment :: pos_integer()
) :: {:allow, non_neg_integer()} | {:deny, non_neg_integer()}

Checks if a key is allowed to perform an action based on the fixed window algorithm.

Link to this function

inc(table, key, scale, increment)

View Source
@spec inc(
  table :: atom(),
  key :: String.t(),
  scale :: pos_integer(),
  increment :: pos_integer()
) :: non_neg_integer()

Increments the counter for a given key in the fixed window algorithm.

Link to this function

set(table, key, scale, count)

View Source
@spec set(
  table :: atom(),
  key :: String.t(),
  scale :: pos_integer(),
  count :: non_neg_integer()
) :: non_neg_integer()

Sets the counter for a given key in the fixed window algorithm.