Home

Awesome

Hammer

Build Status Hex.pm Documentation Total Download License

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 for the latest stable release.


Installation

Hammer is available in Hex. Install by adding :hammer to your list of dependencies in mix.exs:

def deps do
  [
    {:hammer, "~> 7.0"}
  ]
end

Available Backends

Atomic backends are single-node rate limiting but will be the fastest option.

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.

AlgorithmBackend
Hammer.Atomic.FixWindowHammer.Atomic
Hammer.Atomic.LeakyBucketHammer.Atomic
Hammer.Atomic.TokenBucketHammer.Atomic
Hammer.ETS.FixWindowHammer.ETS
Hammer.ETS.LeakyBucketHammer.ETS
Hammer.ETS.TokenBucketHammer.ETS
Hammer.ETS.SlidingWindowHammer.Redis
Hammer.Redis.FixedWindowHammer.Redis

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

Leaky Bucket

Token Bucket

Sliding Window

Selection Guide:

Creating a Rate Limiter

Example Usage

defmodule MyApp.RateLimit do
  use Hammer, backend: :ets
end

MyApp.RateLimit.start_link()

user_id = 42
key = "upload_video:#{user_id}"
scale = :timer.minutes(1)
limit = 3

case 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 for more details.

Acknowledgements

Hammer was originally inspired by the ExRated library, by grempe.

License

Copyright (c) 2023 June Kelly Copyright (c) 2023-2024 See CONTRIBUTORS.md

This library is MIT licensed. See the LICENSE for details.