https://github.com/ExHammer/hammer
An Elixir rate-limiter with pluggable backends
https://github.com/ExHammer/hammer
elixir elixir-lang phoenix phoenix-framework rate-limiter rate-limiting
Last synced: 18 days ago
JSON representation
An Elixir rate-limiter with pluggable backends
- Host: GitHub
- URL: https://github.com/ExHammer/hammer
- Owner: ExHammer
- License: mit
- Created: 2017-06-01T18:21:05.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2025-03-10T08:42:27.000Z (about 1 month ago)
- Last Synced: 2025-03-20T21:26:46.249Z (26 days ago)
- Topics: elixir, elixir-lang, phoenix, phoenix-framework, rate-limiter, rate-limiting
- Language: Elixir
- Homepage: https://hexdocs.pm/hammer/
- Size: 272 KB
- Stars: 819
- Watchers: 4
- Forks: 43
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- freaking_awesome_elixir - Elixir - A rate-limiter with pluggable storage backends, including Redis. (Miscellaneous)
- fucking-awesome-elixir - hammer - A rate-limiter with pluggable storage backends, including Redis. (Miscellaneous)
- awesome-elixir - hammer - A rate-limiter with pluggable storage backends, including Redis. (Miscellaneous)
README
# Hammer
[](https://github.com/ExHammer/hammer/actions/workflows/ci.yml)
[](https://hex.pm/packages/hammer)
[](https://hexdocs.pm/hammer)
[](https://hex.pm/packages/hammer)
[](https://github.com/ExHammer/hammer/blob/master/LICENSE.md)**Hammer** is a rate-limiter for Elixir with pluggable storage backends. Hammer enables users to set limits on actions performed within specified time intervals, applying per-user or global limits on API requests, file uploads, and more.
---
> [!NOTE]
>
> This README is for the unreleased master branch, please reference the [official documentation on hexdocs](https://hexdocs.pm/hammer) for the latest stable release.---
## Installation
Hammer is [available in Hex](https://hex.pm/packages/hammer). Install by adding `:hammer` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:hammer, "~> 7.0"}
]
end
```## Available Backends
Atomic backends are single-node rate limiting but will be the fastest option.
- [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) (default, can be [distributed](./guides/distributed-ets.md))
- [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html)
- [Hammer.Redis](https://github.com/ExHammer/hammer-backend-redis)
- [Hammer.Mnesia](https://github.com/ExHammer/hammer-backend-mnesia)## Available Algorithms:
Each backend supports multiple algorithms. Not all of them are available for all backends. The following table shows which algorithms are available for which backends.
| Algorithm | Backend |
| --------- | ------- |
| [Hammer.Atomic.FixWindow](https://hexdocs.pm/hammer/Hammer.Atomic.FixWindow.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |
| [Hammer.Atomic.LeakyBucket](https://hexdocs.pm/hammer/Hammer.Atomic.LeakyBucket.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |
| [Hammer.Atomic.TokenBucket](https://hexdocs.pm/hammer/Hammer.Atomic.TokenBucket.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |
| [Hammer.ETS.FixWindow](https://hexdocs.pm/hammer/Hammer.ETS.FixWindow.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |
| [Hammer.ETS.LeakyBucket](https://hexdocs.pm/hammer/Hammer.ETS.LeakyBucket.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |
| [Hammer.ETS.TokenBucket](https://hexdocs.pm/hammer/Hammer.ETS.TokenBucket.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |
| [Hammer.ETS.SlidingWindow](https://hexdocs.pm/hammer/Hammer.ETS.SlidingWindow.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |
| [Hammer.Redis.FixedWindow](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.FixedWindow.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |
| [Hammer.Redis.LeakyBucket](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.LeakyBucket.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |
| [Hammer.Redis.TokenBucket](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.TokenBucket.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |
| [Hammer.Mnesia.FixedWindow](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.FixedWindow.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |
| [Hammer.Mnesia.LeakyBucket](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.LeakyBucket.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |
| [Hammer.Mnesia.TokenBucket](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.TokenBucket.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |## Default Algorithm
By default, Hammer backends use the **fixed window counter** to track actions within set time windows, resetting the count at the start of each new window. For example, with a limit of 10 uploads per minute, a user could upload up to 10 files between 12:00:00 and 12:00:59, and up to 10 more between 12:01:00 and 12:01:59. Notice that the user can upload 20 videos in a second if the uploads are timed at the window edges. If this is an issue, it can be worked around with a "bursty" counter which can be implemented with the current API by making two checks, one for the original interval with the total limit, and one for a shorter interval with a fraction of the limit. That would smooth out the number of requests allowed.
## Algorithm Comparison
Here's a comparison of the different rate limiting algorithms to help you choose:
### [Fixed Window](https://hexdocs.pm/hammer/Hammer.Atomic.FixWindow.html)
- Simplest implementation with lowest overhead
- Good for basic rate limiting with clear time boundaries
- Potential edge case: Up to 2x requests possible at window boundaries
- Best for: Basic API limits where occasional bursts are acceptable### [Leaky Bucket](https://hexdocs.pm/hammer/Hammer.Atomic.LeakyBucket.html)
- Provides smooth, consistent request rate
- Requests "leak" out at constant rate
- Good for traffic shaping and steady throughput
- Best for: Network traffic control, queue processing### [Token Bucket](https://hexdocs.pm/hammer/Hammer.Atomic.TokenBucket.html)
- Allows controlled bursts while maintaining average rate
- Tokens regenerate at fixed rate
- More flexible than fixed windows
- Best for: APIs needing burst tolerance, gaming mechanics### [Sliding Window](https://hexdocs.pm/hammer/Hammer.ETS.SlidingWindow.html)
- Most precise rate limiting
- No boundary conditions like fixed windows
- Higher overhead than other algorithms
- Best for: Strict rate enforcement, critical systemsSelection Guide:
- Need simple implementation? → Fixed Window
- Need smooth output rate? → Leaky Bucket
- Need burst tolerance? → Token Bucket
- Need precise limits? → Sliding Window## How to use Hammer
- Basic usage is covered in the [Tutorial](https://hexdocs.pm/hammer/tutorial.html).
- Distributed usage is covered in the [Distributed ETS](https://hexdocs.pm/hammer/distributed-ets.html) guide.## The quick start
- **Limit:** Maximum number of actions allowed in a window.
- **Scale:** Duration of the time window (in milliseconds).
- **Key:** Unique identifier (e.g., user ID) to scope the rate limiting.## Example Usage
```elixir
defmodule MyApp.RateLimit do
use Hammer, backend: :ets
endMyApp.RateLimit.start_link()
user_id = 42
key = "upload_video:#{user_id}"
scale = :timer.minutes(1)
limit = 3case MyApp.RateLimit.hit(key, scale, limit) do
{:allow, _count} ->
# upload the video
:ok{:deny, retry_after} ->
# deny the request
{:error, :rate_limit, _message = "try again in #{retry_after}ms"}
end
```## Benchmarks
See the [BENCHMARKS.md](https://github.com/ExHammer/hammer/blob/master/BENCHMARKS.md) for more details.
## Acknowledgements
Hammer was originally inspired by the [ExRated](https://github.com/grempe/ex_rated) library, by [grempe](https://github.com/grempe).
## License
Copyright (c) 2023 June Kelly
Copyright (c) 2023-2024 See [CONTRIBUTORS.md](https://github.com/ExHammer/hammer/blob/master/CONTRIBUTORS.md)This library is MIT licensed. See the [LICENSE](https://github.com/ExHammer/hammer/blob/master/LICENSE.md) for details.