https://github.com/recruitee/plug_limit
Rate limiting Plug module based on Redis Lua scripting.
https://github.com/recruitee/plug_limit
elixir phoenix phoenix-framework plug rate-limiter rate-limiting
Last synced: 6 months ago
JSON representation
Rate limiting Plug module based on Redis Lua scripting.
- Host: GitHub
- URL: https://github.com/recruitee/plug_limit
- Owner: Recruitee
- License: apache-2.0
- Created: 2022-05-09T12:46:46.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-01-04T15:07:53.000Z (almost 3 years ago)
- Last Synced: 2025-04-14T03:13:46.576Z (6 months ago)
- Topics: elixir, phoenix, phoenix-framework, plug, rate-limiter, rate-limiting
- Language: Elixir
- Homepage:
- Size: 81.1 KB
- Stars: 13
- Watchers: 17
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# PlugLimit
[](https://hex.pm/packages/plug_limit)
[](https://hexdocs.pm/plug_limit)
[](https://github.com/Recruitee/plug_limit/actions/workflows/ci.yml)Rate limiting Plug module based on Redis Lua scripting.
## Summary
PlugLimit is using Redis Lua scripting to provide rate-limiting functionality for web applications
based on a Plug library. PlugLimit has a modular architecture: users can use their own Redis Lua
scripts implementing custom rate limiting algorithms.Salient Redis Lua scripting feature is a race conditions resiliency which makes this library
a recommended solution for distributed systems (e.g.: Phoenix servers behind round robin load balancer).PlugLimit provides two built-in rate limiters: `PlugLimit.FixedWindow` and `PlugLimit.TokenBucket`.
## Installation
Add `PlugLimit` library to your application dependencies:
```elixir
def deps do
[
{:plug_limit, "~> 0.1.0"}
]
end
```## Usage
PlugLimit is Redis client agnostic. In a first step you must define Elixir function executing Redis
commands, depending on Redis client of your choice:
```elixir
# config/config.exs
config :plug_limit,
enabled?: true,
cmd: {MyApp.Redis, :command, []}
````MyApp.Redis.command/2` function must accept Redis command as a first argument and static MFA tuple
`arg` as a second.
In most cases `:cmd` function will be a `Redix.command/3` or `:eredis.q/2,3` wrapper.
Example naive [Redix](https://hex.pm/packages/redix) driver wrapper:
```elixir
#lib/my_app/redis.ex
def command(command, opts \\ [timeout: 500]) do
{:ok, pid} = Redix.start_link()
Redix.command(pid, command, opts)
:ok = Redix.stop(pid)
end
```PlugLimit is tested with both [Redix](https://hex.pm/packages/redix) and
[eredis](https://hex.pm/packages/eredis) Redis clients.Phoenix Framework endpoint can be protected with fixed window rate-limiter by placing a
`PlugLimit.FixedWindow` plug call in the request processing pipeline:
```elixir
#lib/my_app_web/router.ex
pipeline :high_cost_pipeline do
plug(PlugLimit.FixedWindow,
limit: 10,
ttl: 60,
key: {MyApp.RateLimiter, :user_key, [:high_cost_pipeline]}
)
# remaining pipeline plugs...
end
```Rate limits for `:high_cost_pipeline` pipeline will be evaluated with Redis Lua script fixed window
algorithm. Client identified with `:key` will be allowed to issue 10 requests in 60 seconds time
window.MFA tuple defined with `:key` option specifies user function which should provide Redis key
used to uniquely identify given rate-limiter bucket. Redis rate-limiter key name should be derived
from `Plug.Conn.t()` connection struct parameters.
Example function to create Redis key name for rate-limiter throttling requests for a given user
identified by a connection assigned `:user_id`:
```elixir
#lib/my_app/rate_limiter.ex
def user_key(%Plug.Conn{assigns: %{user_id: user_id}}, prefix),
do: {:ok, ["#{prefix}:#{user_id}"]}
```Please refer to `PlugLimit` module documentation for detailed library configuration description and
"Redis Lua script rate limiters" in LIMITERS.md file for Redis Lua scripts implementation
guidelines.## TODO
- [ ] Add leaky bucket rate limiting algorithm implementation.