Tink.RateLimiter (Tink v0.1.1)

Copy Markdown View Source

Rate limiting for Tink API requests using Hammer 7.2.

Uses a private Tink.RateLimiter.Backend module backed by Hammer's fixed-window ETS algorithm. The backend process is supervised by Tink.Application and must be running before any rate-limit functions are called.

Algorithm

Fixed window (Hammer.ETS.FixWindow) is used because Tink's rate limits are expressed as "N requests per hour" — exactly what a fixed window enforces with minimal overhead.

Configuration

config :tink,
  enable_rate_limiting: true

Optionally tune the cleanup interval (default: every 5 minutes):

config :tink, Tink.RateLimiter.Backend,
  clean_period: :timer.minutes(5)

Hammer 7.2 API used

Backend.hit(key, scale_ms, limit) — increments the counter and checks the limit atomically. Returns {:allow, count} or {:deny, ms_to_reset}.

Backend.get(key, scale_ms) — returns the current count without incrementing.

Telemetry

Emits:

  • [:tink, :rate_limit, :checked] — check performed
  • [:tink, :rate_limit, :exceeded] — limit exceeded

Summary

Functions

Checks whether a request is within the configured rate limit.

Returns detailed rate limit information for key.

Returns the number of requests remaining in the current window for key.

Functions

check(key, opts \\ [])

@spec check(
  String.t(),
  keyword()
) :: :ok | {:error, :rate_limited}

Checks whether a request is within the configured rate limit.

Increments the counter for key in the current window. Returns :ok if the request is allowed, or {:error, :rate_limited} if the limit is exceeded.

Parameters

  • key - Bucket identifier, e.g. a user ID or operation name
  • opts - Options:
    • :limit - Maximum requests per window (default: 100)
    • :period - Window duration in milliseconds (default: 1 hour)

Examples

iex> Tink.RateLimiter.check("user_123")
:ok

iex> Tink.RateLimiter.check("user_123", limit: 50, period: :timer.minutes(30))
:ok

info(key, opts \\ [])

@spec info(
  String.t(),
  keyword()
) :: {:ok, map()}

Returns detailed rate limit information for key.

Returns

  • {:ok, map} — Map with :count, :limit, :remaining
  • {:ok, map} — With :resets_in_ms set to 0 when rate limiting is off

Examples

iex> Tink.RateLimiter.info("user_123")
{:ok, %{count: 5, limit: 100, remaining: 95}}

remaining(key, opts \\ [])

@spec remaining(
  String.t(),
  keyword()
) :: {:ok, non_neg_integer() | :infinity}

Returns the number of requests remaining in the current window for key.

Does not increment the counter. Returns {:ok, :infinity} when rate limiting is disabled.

Examples

iex> Tink.RateLimiter.remaining("user_123")
{:ok, 95}

iex> Tink.RateLimiter.remaining("unknown_key")
{:ok, 100}