Kota is a simple rate limiter.

Basic example

{:ok, kota} = Kota.start_link(max_allow: 10, range_ms: 1000, adapter: Kota.Bucket.DiscreteCounter)
:ok = Kota.await(kota)

Adapters

  • Kota.Bucket.DiscreteCounter - This adapter just counts every call at the expense of memory usage.
  • Kota.Bucket.SlidingWindow - This adapter uses a sliding window technique to save on memory and processing but will result in a lower rate if used constantly without time to recover time lost by the window timespan.

Summary

Functions

Blocks the calling process until the rate limiter grants an allowance, then returns :ok.

Returns a specification to start this module under a supervisor.

Returns the current system time in milliseconds.

Starts a rate limiter process without a link to the calling process.

Starts a rate limiter process linked to the calling process.

Synchronously stops the rate limiter process.

Returns the total number of allowances granted by the rate limiter since it started.

Functions

await(server, timeout \\ :infinity)

Blocks the calling process until the rate limiter grants an allowance, then returns :ok.

Callers are served in order of arrival. When the maximum number of allowances for the current time range has been reached, the call waits until an allowance is available again.

iex> {:ok, kota} =
...>   Kota.start_link(
...>     max_allow: 10,
...>     range_ms: 1000,
...>     adapter: Kota.Bucket.SlidingWindow
...>   )
iex> Kota.await(kota)
:ok

The timeout argument accepts :infinity (the default) or a duration in milliseconds. When the timeout is reached before an allowance is granted, the request is removed from the waiting queue and the calling process exits, as with a GenServer.call/3 timeout.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

now_ms()

Returns the current system time in milliseconds.

This is the time source used by the rate limiter and its bucket adapters.

start(opts)

Starts a rate limiter process without a link to the calling process.

Accepts the same options as start_link/1.

start_link(opts)

Starts a rate limiter process linked to the calling process.

iex> {:ok, kota} =
...>   Kota.start_link(
...>     max_allow: 10,
...>     range_ms: 1000,
...>     adapter: Kota.Bucket.DiscreteCounter
...>   )
iex> Kota.await(kota)
:ok

Options

  • :adapter - the bucket implementation, either Kota.Bucket.DiscreteCounter or Kota.Bucket.SlidingWindow. Required.
  • :max_allow - the number of allowances granted within a time range. Required.
  • :range_ms - the duration of the time range, in milliseconds. Required.
  • :slot_ms - the duration of the accounting slots used by Kota.Bucket.SlidingWindow, in milliseconds. Defaults to :one_tenth, which resolves to a tenth of :range_ms and requires :range_ms to be at least 10.
  • :start_time - the timestamp marking the start of the first time range, in milliseconds. Defaults to the current time.

The :name, :debug, :timeout, :spawn_opt and :hibernate_after options of GenServer.start_link/3 are also accepted.

The limiter can also be started as part of a supervision tree:

children = [
  {Kota, max_allow: 10, range_ms: 1000, adapter: Kota.Bucket.SlidingWindow}
]

Supervisor.start_link(children, strategy: :one_for_one)

stop(server)

Synchronously stops the rate limiter process.

total_count(server)

Returns the total number of allowances granted by the rate limiter since it started.

iex> {:ok, kota} =
...>   Kota.start_link(
...>     max_allow: 10,
...>     range_ms: 1000,
...>     adapter: Kota.Bucket.DiscreteCounter
...>   )
iex> :ok = Kota.await(kota)
iex> :ok = Kota.await(kota)
iex> Kota.total_count(kota)
2