The per-minute request limit of a connection, on both sides of it.
Sender. check/1 counts one request against the connection's
rate_limit_requests_per_minute and refuses the request over it with the
seconds until the minute frees. PhoenixKitSync.Connections.authorize_request/3
calls it, and nothing else does: an entry point is limited because it is
authorized, not because it remembered to count.
The counter is core's Hammer backend
(PhoenixKit.Users.RateLimiter.Backend, started by core's supervisor): a
fixed window on the wall clock, held in ETS per node. A sender that runs on
several nodes allows the limit on each of them, and a restart empties it.
A limit of 0 (or nil) is no limit.
Receiver. A sender over its limit answers 429 with Retry-After
(seconds), or "error_code": "rate_limited" with "retry_after" on a
socket. next_wait/2 turns what the sender asked for into the wait this
site is willing to make: the value is the peer's, so it is clamped to
max_wait/0, and the waits of one request together stay within
wait_budget/0. Both are seconds and come from app env:
config :phoenix_kit_sync,
rate_limit_max_wait_seconds: 60,
rate_limit_wait_budget_seconds: 300
Summary
Functions
Counts one request under connection.
Counts one request in key's current window of window_ms, allowing
limit of them. check/1 with the window as an argument.
The longest single wait, in seconds (rate_limit_max_wait_seconds, default 60).
The seconds to wait before asking a rate-limited sender again.
The most one request waits in total, in seconds
(rate_limit_wait_budget_seconds, default 300).
Types
@type refusal() :: {:error, {:rate_limited, pos_integer()}}
Functions
@spec check(PhoenixKitSync.Connection.t()) :: :ok | refusal()
Counts one request under connection.
Returns :ok, or {:error, {:rate_limited, seconds}} for a request past
the connection's limit in the current minute, with the seconds until that
minute ends.
@spec hit(String.t(), pos_integer(), pos_integer()) :: :ok | refusal()
Counts one request in key's current window of window_ms, allowing
limit of them. check/1 with the window as an argument.
@spec max_wait() :: pos_integer()
The longest single wait, in seconds (rate_limit_max_wait_seconds, default 60).
@spec next_wait(term(), non_neg_integer()) :: {:wait, pos_integer()} | :give_up
The seconds to wait before asking a rate-limited sender again.
retry_after is what the sender sent (a header value, a JSON number, or
nothing) and waited the seconds this request has waited already. Returns
{:wait, seconds} with the value clamped between 1 and max_wait/0, or
:give_up when that wait would pass wait_budget/0.
A value that is not a whole number of seconds (missing, text, an HTTP date) reads as 5 seconds.
@spec wait_budget() :: pos_integer()
The most one request waits in total, in seconds
(rate_limit_wait_budget_seconds, default 300).