View Source Hammer.ETS.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:
- 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
- To check if rate limit is exceeded:
- If count <= limit: allow request
- If count > limit: deny and return time until window expires
- 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
Cleans up all of the old entries from the table.
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 clean(config :: Hammer.ETS.config()) :: non_neg_integer()
Cleans up all of the old entries from the table.
@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.
@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.
@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.
@spec set( table :: atom(), key :: String.t(), scale :: pos_integer(), count :: pos_integer() ) :: integer()
Sets the counter for a given key in the fixed window algorithm.