# RateLimiterMan
> #### Warning {: .warning}
>
> 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](https://akoutmos.com/post/rate-limiting-with-genservers/).
> #### Warning {: .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`:
```elixir
{:rate_limiter_man, "0.2.2"}
```
### Configure your application
Add the config for your rate limiter instance:
`config/config.exs`
```elixir
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 {: .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`
```elixir
defmodule YourProject.Application do
use Application
@impl true
def start(_type, _args) do
children =
[
# Add a task supervisor. This only needs to be added once:
RateLimiterMan.add_task_supervisor(),
# Add one of these lines for each rate limiter instance. 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)
]
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