{"id":15667634,"url":"https://github.com/exhammer/hammer","last_synced_at":"2025-05-13T20:12:18.584Z","repository":{"id":21522021,"uuid":"93086929","full_name":"ExHammer/hammer","owner":"ExHammer","description":"An Elixir rate-limiter with pluggable backends","archived":false,"fork":false,"pushed_at":"2025-04-21T10:06:45.000Z","size":289,"stargazers_count":830,"open_issues_count":2,"forks_count":43,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-28T10:57:51.387Z","etag":null,"topics":["elixir","elixir-lang","phoenix","phoenix-framework","rate-limiter","rate-limiting"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/hammer/","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ExHammer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-06-01T18:21:05.000Z","updated_at":"2025-04-24T10:32:34.000Z","dependencies_parsed_at":"2023-01-13T21:32:15.777Z","dependency_job_id":"ef42b2ee-17f3-466a-9caf-8f0c7a149fa6","html_url":"https://github.com/ExHammer/hammer","commit_stats":{"total_commits":227,"total_committers":13,"mean_commits":17.46153846153846,"dds":"0.21145374449339205","last_synced_commit":"8c7a5b2f2940c615b5ae23ee5b67e5c5a6fc0a72"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExHammer%2Fhammer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExHammer%2Fhammer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExHammer%2Fhammer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExHammer%2Fhammer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ExHammer","download_url":"https://codeload.github.com/ExHammer/hammer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254020615,"owners_count":22000755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","elixir-lang","phoenix","phoenix-framework","rate-limiter","rate-limiting"],"created_at":"2024-10-03T14:04:35.581Z","updated_at":"2025-05-13T20:12:18.534Z","avatar_url":"https://github.com/ExHammer.png","language":"Elixir","readme":"# Hammer\n\n[![Build Status](https://github.com/ExHammer/hammer/actions/workflows/ci.yml/badge.svg)](https://github.com/ExHammer/hammer/actions/workflows/ci.yml)\n[![Hex.pm](https://img.shields.io/hexpm/v/hammer.svg)](https://hex.pm/packages/hammer)\n[![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/hammer)\n[![Total Download](https://img.shields.io/hexpm/dt/hammer.svg)](https://hex.pm/packages/hammer)\n[![License](https://img.shields.io/hexpm/l/hammer.svg)](https://github.com/ExHammer/hammer/blob/master/LICENSE.md)\n\n**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.\n\n---\n\n\u003e [!NOTE]\n\u003e\n\u003e This README is for the unreleased master branch, please reference the [official documentation on hexdocs](https://hexdocs.pm/hammer) for the latest stable release.\n\n---\n\n## Installation\n\nHammer is [available in Hex](https://hex.pm/packages/hammer). Install by adding `:hammer` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:hammer, \"~\u003e 7.0\"}\n  ]\nend\n```\n\n## Available Backends\n\nAtomic backends are single-node rate limiting but will be the fastest option.\n\n- [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) (default, can be [distributed](./guides/distributed-ets.md))\n- [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html)\n- [Hammer.Redis](https://github.com/ExHammer/hammer-backend-redis)\n- [Hammer.Mnesia](https://github.com/ExHammer/hammer-backend-mnesia)\n\n## Available Algorithms:\n\nEach backend supports multiple algorithms. Not all of them are available for all backends. The following table shows which algorithms are available for which backends.\n\n| Algorithm | Backend |\n| --------- | ------- |\n| [Hammer.Atomic.FixWindow](https://hexdocs.pm/hammer/Hammer.Atomic.FixWindow.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |\n| [Hammer.Atomic.LeakyBucket](https://hexdocs.pm/hammer/Hammer.Atomic.LeakyBucket.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |\n| [Hammer.Atomic.TokenBucket](https://hexdocs.pm/hammer/Hammer.Atomic.TokenBucket.html) | [Hammer.Atomic](https://hexdocs.pm/hammer/Hammer.Atomic.html) |\n| [Hammer.ETS.FixWindow](https://hexdocs.pm/hammer/Hammer.ETS.FixWindow.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |\n| [Hammer.ETS.LeakyBucket](https://hexdocs.pm/hammer/Hammer.ETS.LeakyBucket.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |\n| [Hammer.ETS.TokenBucket](https://hexdocs.pm/hammer/Hammer.ETS.TokenBucket.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |\n| [Hammer.ETS.SlidingWindow](https://hexdocs.pm/hammer/Hammer.ETS.SlidingWindow.html) | [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) |\n| [Hammer.Redis.FixedWindow](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.FixedWindow.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |\n| [Hammer.Redis.LeakyBucket](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.LeakyBucket.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |\n| [Hammer.Redis.TokenBucket](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.TokenBucket.html) | [Hammer.Redis](https://hexdocs.pm/hammer_backend_redis/Hammer.Redis.html) |\n| [Hammer.Mnesia.FixedWindow](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.FixedWindow.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |\n| [Hammer.Mnesia.LeakyBucket](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.LeakyBucket.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |\n  | [Hammer.Mnesia.TokenBucket](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.TokenBucket.html) | [Hammer.Mnesia](https://hexdocs.pm/hammer_backend_mnesia/Hammer.Mnesia.html) |\n\n## Default Algorithm\n\nBy 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.\n\n## Algorithm Comparison\n\nHere's a comparison of the different rate limiting algorithms to help you choose:\n\n### [Fixed Window](https://hexdocs.pm/hammer/Hammer.Atomic.FixWindow.html)\n- Simplest implementation with lowest overhead\n- Good for basic rate limiting with clear time boundaries\n- Potential edge case: Up to 2x requests possible at window boundaries\n- Best for: Basic API limits where occasional bursts are acceptable\n\n### [Leaky Bucket](https://hexdocs.pm/hammer/Hammer.Atomic.LeakyBucket.html)\n- Provides smooth, consistent request rate\n- Requests \"leak\" out at constant rate\n- Good for traffic shaping and steady throughput\n- Best for: Network traffic control, queue processing\n\n### [Token Bucket](https://hexdocs.pm/hammer/Hammer.Atomic.TokenBucket.html)\n- Allows controlled bursts while maintaining average rate\n- Tokens regenerate at fixed rate\n- More flexible than fixed windows\n- Best for: APIs needing burst tolerance, gaming mechanics\n\n### [Sliding Window](https://hexdocs.pm/hammer/Hammer.ETS.SlidingWindow.html)\n- Most precise rate limiting\n- No boundary conditions like fixed windows\n- Higher overhead than other algorithms\n- Best for: Strict rate enforcement, critical systems\n\nSelection Guide:\n- Need simple implementation? → Fixed Window\n- Need smooth output rate? → Leaky Bucket\n- Need burst tolerance? → Token Bucket\n- Need precise limits? → Sliding Window\n\n## How to use Hammer\n\n- Basic usage is covered in the [Tutorial](https://hexdocs.pm/hammer/tutorial.html).\n- Distributed usage is covered in the [Distributed ETS](https://hexdocs.pm/hammer/distributed-ets.html) guide.\n\n## The quick start\n\n- **Limit:** Maximum number of actions allowed in a window.\n- **Scale:** Duration of the time window (in milliseconds).\n- **Key:** Unique identifier (e.g., user ID) to scope the rate limiting.\n\n## Example Usage\n\n```elixir\ndefmodule MyApp.RateLimit do\n  use Hammer, backend: :ets\nend\n\nMyApp.RateLimit.start_link()\n\nuser_id = 42\nkey = \"upload_video:#{user_id}\"\nscale = :timer.minutes(1)\nlimit = 3\n\ncase MyApp.RateLimit.hit(key, scale, limit) do\n  {:allow, _count} -\u003e\n    # upload the video\n    :ok\n\n  {:deny, retry_after} -\u003e\n    # deny the request\n    {:error, :rate_limit, _message = \"try again in #{retry_after}ms\"}\nend\n```\n\n## Benchmarks\n\nSee the [BENCHMARKS.md](https://github.com/ExHammer/hammer/blob/master/BENCHMARKS.md) for more details.\n\n## Acknowledgements\n\nHammer was originally inspired by the [ExRated](https://github.com/grempe/ex_rated) library, by [grempe](https://github.com/grempe).\n\n## License\n\nCopyright (c) 2023 June Kelly\nCopyright (c) 2023-2024 See [CONTRIBUTORS.md](https://github.com/ExHammer/hammer/blob/master/CONTRIBUTORS.md)\n\nThis library is MIT licensed. See the [LICENSE](https://github.com/ExHammer/hammer/blob/master/LICENSE.md) for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexhammer%2Fhammer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexhammer%2Fhammer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexhammer%2Fhammer/lists"}