ETS-backed token bucket rate limiter with per-tenant isolation.
Each tenant (or :global for single-tenant deployments) gets its own
token bucket. Buckets are refilled on a configurable interval.
Plaid's rate limits vary by plan and endpoint. This limiter acts as a
client-side guard to prevent hammering Plaid before their server responds
with RATE_LIMIT_EXCEEDED. When Plaid does return a rate limit error,
the HTTP client's retry logic handles it with backoff.
Architecture
Uses a GenServer to own the ETS table (so the table survives the
calling process crashing) with an ETS-based fast path for the common
check case. Refill happens via Process.send_after.
Bucket defaults
:global— 200 requests/second (conservative Plaid production limit)- Per-tenant — 50 requests/second (safe default for multi-tenant)
Override by calling configure_tenant/2.
Summary
Functions
Checks whether a request is allowed under the current rate limit.
Returns a specification to start this module under a supervisor.
Configures a custom rate limit for a specific tenant.
Functions
@spec check(String.t() | :global, PlaidEx.Config.t()) :: :ok | {:error, :rate_limited}
Checks whether a request is allowed under the current rate limit.
Returns :ok if allowed, {:error, :rate_limited} if the bucket
is empty. Does NOT block — callers should treat :rate_limited as
a fast-fail signal and apply their own backoff.
Returns a specification to start this module under a supervisor.
See Supervisor.
Configures a custom rate limit for a specific tenant.
PlaidEx.HTTP.RateLimiter.configure_tenant("acme", requests_per_second: 100)
@spec start_link(keyword()) :: GenServer.on_start()