README.md

![Elixir CI](https://github.com/4xposed/minirate/workflows/Elixir%20CI/badge.svg?event=push)

# Minirate

A dead simple distributed rate limiting library in Elixir using Mnesia.

# What is it?

A distributed rate limiter with a focus on readable and well tested code.

The counter is syncronized over all connected nodes

```elixir
iex(test2@127.0.0.1)19> Minirate.check_limit("download", "user_1", 100)
{:allow, 1}
```
```elixir
iex(test1@127.0.0.1)14> Minirate.check_limit("download", "user_1", 100)
{:allow, 2}
```

## Installation

Minirate is availabe as a package in Hex, just add it to your `mix.exs` file:

```elixir
def deps
  [{:minirate, "~> 0.1"}]
end
```

and add it to your extra applications:
```elixir
def applications do
[
  extra_applications: [:minirate]
]
```

## Configuration

Minirate needs to be configured using Mix.Config.

For example, in `config/config.exs`:

```
config :minirate,
  mnesia_table: :rate_limiter,
  expiry_ms: 60_000
  cleanup_period_ms: 10_000
```

`mnesia_table` specifies which table will Mnesia use to write the counters.
`expiry_ms` specifies the counter life in millisecconds (for example to have rates like x request every 10 seconds, you would set `expiry_ms` to 10_000)
`cleanup_period_ms` specifies how often minirate will clean expired counters from the mnesia database


## Usage

With Minirate you can rate limit any action on your application.

The module `Minirate` the function `check_limit(action_name, identifier, limit)`

An Example:

```elixir
@download_limit 1_000

def download_file(file, user_id) do
  case Minirate.check_limit("download_file", user_id, @download_limit) do
    {:allow, _count} ->
      # Logic to download the file

    {:block, _reason} ->
      # Logic when the limit has been reached

    {:skip, _reason} ->
     # Skip will only happen if there's a problem with your nodes or mnesia setup and a count cannot be determined.
  end
```

## Using Minirate.Plug

`Minirate.Plug` can rate-limit actions in your web application using the ip address of the requester.

You can just put in the pipeline of your web application something like this:

```elixir
plug Minirate.Plug, [action: action, limit: 10_000]
```

or for more flexibilty:
```elixir
plug Minirate.Plug, [action: "custom_action", limit: 10_000] when action == :update or action == :create
```