use Croma defmodule Foretoken do @moduledoc File.read!(Path.join([__DIR__, "..", "README.md"])) |> String.replace_prefix("# #{inspect(__MODULE__)}\n\n", "") @doc """ 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/4`; 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. """ defun take(bucket :: any, milliseconds_per_token :: g[pos_integer], max_tokens :: g[pos_integer], tokens_to_take :: g[pos_integer] \\ 1) :: :ok | {:error, pos_integer} do if tokens_to_take <= max_tokens do Foretoken.Ets.take(bucket, tokens_to_take, milliseconds_per_token, max_tokens) else raise ArgumentError, "`tokens_to_take` cannot exceed `max_tokens`" end end end