# `Foretoken`
[🔗](https://github.com/skirino/foretoken/blob/main/lib/foretoken.ex#L3)

An ETS-based implementation of the [token bucket algorithm](https://en.wikipedia.org/wiki/Token_bucket).

- [API Documentation](http://hexdocs.pm/foretoken/)
- [Hex package information](https://hex.pm/packages/foretoken)

[![Hex.pm](http://img.shields.io/hexpm/v/foretoken.svg)](https://hex.pm/packages/foretoken)
[![Coverage Status](https://coveralls.io/repos/github/skirino/foretoken/badge.svg?branch=master)](https://coveralls.io/github/skirino/foretoken?branch=master)

## Feature & Design

- Simplest possible API (only 1 public interface function: `Foretoken.take/5`)
- ETS as concurrently accessible bucket storage
- Bucket lifecycle management
    - On-demand creation of buckets (whch can be disabled)
    - Automatic cleanup of unused buckets

## Compatibility notes

This package requires Erlang/OTP 20 (or later).

---

See also `Foretoken.Config`.

# `reason`

```elixir
@type reason() ::
  {:not_enough_token, milliseconds_to_wait :: pos_integer()}
  | :nonexisting_bucket
```

# `take`

```elixir
@spec take(
  any(),
  pos_integer(),
  pos_integer(),
  pos_integer(),
  boolean()
) :: :ok | {:error, reason()}
```

Tries to take the specified number of token(s) from the bucket identified by `bucket`.

If the specified bucket does not exist, it's created on-demand filled with `max_tokens` tokens.
If the bucket exists, current number of tokens is computed (using `milliseconds_per_token` and `max_tokens`)
and, if available, `tokens_to_take` tokens are removed from the bucket.
When there are no enough tokens in the bucket this function returns `{:error, milliseconds_to_wait}`,
where `milliseconds_to_wait` is the duration after which the requested tokens become available.
Note that waiting for `milliseconds_to_wait` doesn't guarantee success at the next `take/5`;
another concurrent process may precede the current process.

Although you can use basically arbitrary term for `bucket` argument,
atoms with `$` and integers (such as `:"$1"`, `:"$2"`, ...) are not usable.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
