Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New API #104

Merged
merged 48 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4a9dce5
update runtime and deps
ruslandoga Nov 13, 2024
981bc83
quick cleanup
ruslandoga Nov 13, 2024
85b4b2a
add erl 27, ex 1.17 to ci
ruslandoga Nov 13, 2024
8cdf9da
begin
ruslandoga Nov 13, 2024
4ea9b0f
cleanup
ruslandoga Nov 13, 2024
76e38b1
add ets backend
ruslandoga Nov 13, 2024
b384c53
add tests
ruslandoga Nov 13, 2024
00711e1
only keep latest runtimes
ruslandoga Nov 13, 2024
a3fc301
remove unused poolboy from lock
ruslandoga Nov 13, 2024
4675f6d
heppy credo
ruslandoga Nov 13, 2024
03f14af
small refactor
ruslandoga Nov 13, 2024
3fbb64e
try before_compile
ruslandoga Nov 13, 2024
1c8d9b1
update guides
ruslandoga Nov 13, 2024
092f65c
fix ci?
ruslandoga Nov 13, 2024
4954867
fix ci? x2
ruslandoga Nov 13, 2024
bb58807
add utility functions
ruslandoga Nov 13, 2024
17fc5c7
add wait
ruslandoga Nov 13, 2024
1a147ab
hm
ruslandoga Nov 13, 2024
9d94f23
full coverage
ruslandoga Nov 13, 2024
6ab5abb
update more docs
ruslandoga Nov 13, 2024
0e22e3d
rm image
ruslandoga Nov 13, 2024
58ccb44
mark ets as the default
ruslandoga Nov 13, 2024
2d859a9
eh
ruslandoga Nov 13, 2024
5076c2f
eh
ruslandoga Nov 13, 2024
8feb1df
add distributed ets example
ruslandoga Nov 13, 2024
19817b9
improve distributed ets example
ruslandoga Nov 13, 2024
2e2231e
improve distributed ets example
ruslandoga Nov 13, 2024
5865d3e
annotate
ruslandoga Nov 13, 2024
044c092
add inc, make hit return more info, remove check_rate
ruslandoga Nov 14, 2024
87549a1
remove check_rate mentions
ruslandoga Nov 14, 2024
b8d7e6b
update distributed ets example
ruslandoga Nov 14, 2024
40d8b26
rename wait to retry_after
ruslandoga Nov 14, 2024
91c1925
Update distributed-ets.md
ruslandoga Nov 16, 2024
790351e
Update distributed-ets.md
ruslandoga Nov 16, 2024
0f2ebd2
Update README.md
ruslandoga Nov 16, 2024
378a76f
Update README.md
ruslandoga Nov 16, 2024
c00d95e
Update README.md
ruslandoga Nov 16, 2024
25929cf
Update README.md
ruslandoga Nov 16, 2024
945794b
Update ets.ex
ruslandoga Nov 16, 2024
430dcd7
eh
ruslandoga Nov 16, 2024
2995b0f
eh
ruslandoga Nov 17, 2024
c943628
updating some docs per comments
epinault Dec 4, 2024
2152362
update matrix support
epinault Dec 4, 2024
9531f17
wrote the upgrade guide. Updated changelog
epinault Dec 5, 2024
094e596
adds publishing on tagging master
epinault Dec 5, 2024
e829747
remove TODO to pass lint.
epinault Dec 5, 2024
bb9d03d
fix matrix
epinault Dec 5, 2024
e08decb
fix to minimum elixir 1.14
epinault Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
inputs: ["{mix,.formatter}.exs", "{lib,test}/**/*.{ex,exs}"]
]
58 changes: 34 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,66 @@ name: CI

on:
pull_request:
branches:
- master
push:
branches:
- master
branches: [master]

jobs:
setup:
test:
runs-on: ${{ matrix.os }}

env:
MIX_ENV: test

strategy:
fail-fast: false
# https://hexdocs.pm/elixir/compatibility-and-deprecations.html#between-elixir-and-erlang-otp
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
elixir_version: [1.13, 1.14, 1.15, 1.16]
otp_version: [24, 25, 26]
os: [ubuntu-22.04, ubuntu-24.04]
elixir: [1.17, 1.16, 1.15, 1.14]
otp: [27, 26, 25]
include:
- elixir: 1.17
otp: 27
exclude:
- otp_version: 26
elixir_version: 1.13

runs-on: ${{ matrix.os }}
- elixir: 1.14
otp: 26
- elixir: 1.14
otp: 27
- elixir: 1.15
otp: 27
- elixir: 1.16
otp: 27

steps:
- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp_version}}
elixir-version: ${{matrix.elixir_version}}
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}

- uses: actions/cache@v4
with:
path: |
deps
_build
key: deps-${{ runner.os }}-${{ matrix.otp_version }}-${{ matrix.elixir_version }}-${{ hashFiles('**/mix.lock') }}
key: test-otp-${{ matrix.otp }}-elixir-${{ matrix.elixir }}-ref-${{ github.head_ref || github.ref }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: |
deps-${{ runner.os }}-${{ matrix.otp_version }}-${{ matrix.elixir_version }}
test-otp-${{ matrix.otp }}-elixir-${{ matrix.elixir }}-ref-${{ github.head_ref || github.ref }}-mix-
test-otp-${{ matrix.otp }}-elixir-${{ matrix.elixir }}-ref-refs/heads/master-mix-
- run: mix deps.get

- run: mix format --check-formatted

- run: mix deps.unlock --check-unused

- run: mix deps.compile

- run: mix compile --warnings-as-errors

- run: mix credo --strict --format=oneline

- run: mix test --warnings-as-errors --cover

format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
elixir-version: 1
otp-version: 27
- run: mix format --check-formatted
18 changes: 18 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Publish

on:
push:
tags:
- "*"

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v4

- name: Publish package to hex.pm
uses: hipcall/github_action_publish_hex@v1
env:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.16.3-otp-26
erlang 26.2.5
elixir 1.17.3-otp-27
erlang 27.1.2
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changelog

## Unreleased
## 7.0.0-rc.0 - 2024-12-04

- Breaking change. Completely new API. Consider upgrading if you are experiencing performance or usability problems with Hammer v6. See [./guides/upgrade-v7.md] for upgrade instructions. https://github.com/ExHammer/hammer/pull/104
- Hammer.Plug has been removed. See documentation for using Hammer as a plug in Phoenix.

## 6.2.1 - 2024-02-23

Expand All @@ -10,7 +13,7 @@

## 6.2.0 - 2024-01-31

- Ensure Elixir version is ~> 1.13 https://github.com/ExHammer/hammer/pull/79.
- Ensure Elixir version is ~> 1.13 https://github.com/ExHammer/hammer/pull/79.

## 6.1.0 - 2022-06-13

Expand Down
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Thanks to our Contributors as well:
- [Gary Rennie](https://github.com/Gazler)
- [Ross Wilson](https://github.com/rosswilson)
- [Emmanuel Pinault](https://github.com/epinault)
- [ruslandoga](https://github.com/ruslandoga)
83 changes: 32 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,69 @@
<img src="assets/horizontal.svg" alt="hammer" height="150px">

# Hammer

[![Build Status](https://github.com/ExHammer/hammer/actions/workflows/ci.yml/badge.svg)](https://github.com/ExHammer/hammer/actions/workflows/ci.yml) [![Hex.pm](https://img.shields.io/hexpm/v/hammer.svg)](https://hex.pm/packages/hammer) [![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/hammer)
[![Build Status](https://github.com/ExHammer/hammer/actions/workflows/ci.yml/badge.svg)](https://github.com/ExHammer/hammer/actions/workflows/ci.yml)
[![Hex.pm](https://img.shields.io/hexpm/v/hammer.svg)](https://hex.pm/packages/hammer)
[![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/hammer)
[![Total Download](https://img.shields.io/hexpm/dt/hammer.svg)](https://hex.pm/packages/hammer)
[![License](https://img.shields.io/hexpm/l/hammer.svg)](https://github.com/ExHammer/hammer/blob/master/LICENSE.md)

A rate-limiter for Elixir, with pluggable storage backends.

## Hammer-Plug

We have a helper-library to make adding rate-limiting to your Phoenix
(or other plug-based) application even easier: [Hammer.Plug](https://github.com/ExHammer/hammer-plug).
**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.

## Installation

Hammer is [available in Hex](https://hex.pm/packages/hammer), the package can be installed
by adding `:hammer` to your list of dependencies in `mix.exs`:
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, "~> 6.1"}
{:hammer, "~> 7.0"}
]
end
```

## Documentation
## Default Algorithm

On HexDocs: [https://hexdocs.pm/hammer/frontpage.html](https://hexdocs.pm/hammer/frontpage.html)
By default, Hammer uses a **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.

The [Tutorial](https://hexdocs.pm/hammer/tutorial.html) is an especially good place to start.
## Core Concepts

## Usage
- **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:
## Example Usage

```elixir
defmodule MyApp.VideoUpload do

def upload(video_data, user_id) do
case Hammer.check_rate("upload_video:#{user_id}", 60_000, 5) do
{:allow, _count} ->
# upload the video, somehow
{:deny, _limit} ->
# deny the request
end
end

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

The `Hammer` module provides the following functions:
MyApp.RateLimit.start_link()

- `check_rate(id, scale_ms, limit)`
- `check_rate_inc(id, scale_ms, limit, increment)`
- `inspect_bucket(id, scale_ms, limit)`
- `delete_buckets(id)`
user_id = 42
key = "upload_video:#{user_id}"
scale = :timer.minutes(1)
limit = 3

Backends are configured via `Mix.Config`:
case MyApp.RateLimit.hit(key, scale, limit) do
{:allow, _count} ->
# upload the video
:ok

```elixir
config :hammer,
backend: {Hammer.Backend.ETS, [expiry_ms: 60_000 * 60 * 4,
cleanup_interval_ms: 60_000 * 10]}
{:deny, retry_after} ->
# deny the request
{:error, :rate_limit, _message = "try again in #{retry_after}ms"}
end
```

See the [Tutorial](https://hexdocs.pm/hammer/tutorial.html) for more.

See the [Hammer Testbed](https://github.com/ExHammer/hammer-testbed) app for an example of
using Hammer in a Phoenix application.

## Available Backends

- [Hammer.Backend.ETS](https://hexdocs.pm/hammer/Hammer.Backend.ETS.html) (provided with Hammer for testing and dev purposes, not very good for production use)
- [Hammer.Backend.Redis](https://github.com/ExHammer/hammer-backend-redis)
- [Hammer.Backend.Mnesia](https://github.com/ExHammer/hammer-backend-mnesia) (beta)

## Getting Help
- [Hammer.ETS](https://hexdocs.pm/hammer/Hammer.ETS.html) (default, can be [distributed](./guides/distributed-ets.md))
- [Hammer.Redis](https://github.com/ExHammer/hammer-backend-redis)
- [Hammer.Mnesia](https://github.com/ExHammer/hammer-backend-mnesia)

If you're having trouble, either open an issue on this repo
## Acknowledgements

Hammer was inspired by the [ExRated](https://github.com/grempe/ex_rated) library, by [grempe](https://github.com/grempe).
Hammer was originally inspired by the [ExRated](https://github.com/grempe/ex_rated) library, by [grempe](https://github.com/grempe).

## License

Expand Down
12 changes: 0 additions & 12 deletions config/config.exs

This file was deleted.

5 changes: 0 additions & 5 deletions coveralls.json

This file was deleted.

79 changes: 0 additions & 79 deletions guides/CreatingBackends.md

This file was deleted.

30 changes: 0 additions & 30 deletions guides/Frontpage.md

This file was deleted.

Loading
Loading