RateLimiterMan
View SourceWarning
This is a very early release. It works but has some rough edges, and shouldn't be considered production-ready for most use cases. It is probably not the most performant implementation out there, but it solves the need for which it was created.
A simple rate limiter implementation, adapted from a blog post by Alex Koutmous.
Warning
Currently, only the leaky bucket rate limiter algorithm is implemented by this package.
This package supports multiple rate limiter instances in your application. Just follow the instructions, using a different config key for each rate limiter you want to add.
Getting started
Install the package
Add this package to your list of dependencies in mix.exs
, then run mix deps.get
:
{:rate_limiter_man, "0.2.3"}
Configure your application
Add the config for your rate limiter instance:
config/config.exs
import Config
config :your_project, YourProject.SomeApi,
# Required items
rate_limiter_algorithm: RateLimiterMan.LeakyBucket,
rate_limiter_max_requests_per_second: 1
# Optional items
## rate_limiter_logger_level: :debug # Enable logging when the rate limiter handles a request
Warning
The log statements may contain sensitive data (e.g. API keys). There is currently no way of modifying the contents of the Logger statement.
Add the rate limiter to your application's supervision tree
lib/your_project/application.ex
defmodule YourProject.Application do
use Application
@impl true
def start(_type, _args) do
children =
[
# Add the task supervisor before adding any rate limiters. The task supervisor should only
# be declared once
RateLimiterMan.add_task_supervisor(),
# Add the desired rate limiter(s). The OTP app name and config key must match the app name
# and key used in your config file
RateLimiterMan.add_rate_limiter(:your_project, YourProject.SomeApi),
# RateLimiterMan.add_rate_limiter(:your_project, YourProject.SomeOtherApi),
# RateLimiterMan.add_rate_limiter(:your_project, YourProject.YetAnotherApi)
]
opts = [strategy: :one_for_one, name: YourProject.Supervisor]
Supervisor.start_link(children, opts)
end
end
Now, the rate limiter process will start working when you start your application: iex -S mix
Example: Use the rate limiter when making a request
Any function can be passed to the rate limiter. For simplicity, this example will not make any HTTP requests.
lib/your_project/some_api.ex
defmodule YourProject.SomeApi do
def hello_world do
request_id = System.unique_integer()
# Make the request
RateLimiterMan.make_request(
_otp_app = :your_project,
_config_key = YourProject.SomeApi,
_request_handler = {Enum, :join, [["Hello", "world!"], " "]},
send_response_to_pid: self(),
request_id: request_id
)
# Receive the response
response = RateLimiterMan.receive_response(request_id, _timeout = :timer.seconds(5))
IO.puts(response)
response
end
end
Let's try it out. Start an interactive shell with iex -S mix
:
iex> for _ <- 1..3, do: YourProject.SomeApi.hello_world()
Hello world!
Hello world!
Hello world!
["Hello world!", "Hello world!", "Hello world!"]
If you set your rate limiter with the config in the instructions, you should see the phrase "Hello world!" printed to the terminal 3 times, and the rate limiter ensured that only one "request" was handled every second.
If everything worked, you can now adapt the rate limiter for use in your application.
More information
Project documentation: https://hexdocs.pm/rate_limiter_man
Hex package: https://hex.pm/rate_limiter_man