Skip to content

Repository files navigation

PlugLimit

Hex Version Hex Docs CI

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:

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:

# 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 driver wrapper:

#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 and 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:

#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:

#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.

About

Rate limiting Plug module based on Redis Lua scripting.

Topics

Resources

Stars

13 stars

Watchers

15 watching

Forks

Releases

Used by

Contributors

Languages