glimit

This module provides a distributed rate limiter that can be used to limit the number of requests or function calls per second for a given identifier.

A single actor is used to assign one rate limiter actor per identifier. The rate limiter actor then uses a Token Bucket algorithm to determine if a request or function call should be allowed to proceed. A separate process is polling the rate limiters to remove full buckets to reduce unnecessary memory usage.

The rate limits are configured using the following two options:

The rate limiter can be applied to a function or handler using the apply function, which returns a new function that checks the rate limit before calling the original function.

Example

import glimit

let limiter =
  glimit.new()
  |> glimit.per_second(10)
  |> glimit.burst_limit(100)
  |> glimit.identifier(fn(request) { request.ip })
  |> glimit.on_limit_exceeded(fn(_request) { "Rate limit reached" })
  |> glimit.build()

let handler =
  fn(_request) { "Hello, world!" }
  |> glimit.apply(limiter)

Types

A rate limiter.

pub type RateLimiter(a, b, id) {
  RateLimiter(
    rate_limiter_registry: RateLimiterRegistryActor(id),
    on_limit_exceeded: fn(a) -> b,
    identifier: fn(a) -> id,
  )
}

Constructors

  • RateLimiter(
      rate_limiter_registry: RateLimiterRegistryActor(id),
      on_limit_exceeded: fn(a) -> b,
      identifier: fn(a) -> id,
    )

A builder for configuring the rate limiter.

pub type RateLimiterBuilder(a, b, id) {
  RateLimiterBuilder(
    per_second: Option(Int),
    burst_limit: Option(Int),
    identifier: Option(fn(a) -> id),
    on_limit_exceeded: Option(fn(a) -> b),
  )
}

Constructors

  • RateLimiterBuilder(
      per_second: Option(Int),
      burst_limit: Option(Int),
      identifier: Option(fn(a) -> id),
      on_limit_exceeded: Option(fn(a) -> b),
    )

Functions

pub fn apply(
  func: fn(a) -> b,
  limiter: RateLimiter(a, b, c),
) -> fn(a) -> b

Apply the rate limiter to a request handler or function.

pub fn build(
  config: RateLimiterBuilder(a, b, c),
) -> RateLimiter(a, b, c)

Build the rate limiter.

Panics if the rate limiter registry cannot be started or if the identifier function or on_limit_exceeded function is missing.

To handle errors instead of panicking, use try_build.

pub fn burst_limit(
  limiter: RateLimiterBuilder(a, b, c),
  burst_limit: Int,
) -> RateLimiterBuilder(a, b, c)

Set the maximum number of available tokens.

The maximum number of available tokens is the maximum number of requests that can be made in a single second. The default value is the same as the rate limit per second.

pub fn identifier(
  limiter: RateLimiterBuilder(a, b, c),
  identifier: fn(a) -> c,
) -> RateLimiterBuilder(a, b, c)

Set the identifier function to be used to identify the rate limit.

pub fn new() -> RateLimiterBuilder(a, b, c)

Create a new rate limiter builder.

pub fn on_limit_exceeded(
  limiter: RateLimiterBuilder(a, b, c),
  on_limit_exceeded: fn(a) -> b,
) -> RateLimiterBuilder(a, b, c)

Set the handler to be called when the rate limit is reached.

pub fn per_second(
  limiter: RateLimiterBuilder(a, b, c),
  limit: Int,
) -> RateLimiterBuilder(a, b, c)

Set the rate limit per second.

The value is not only used for the rate at which tokens are added to the bucket, but also for the maximum number of available tokens. To set a different value fo the maximum number of available tokens, use the burst_limit function.

pub fn try_build(
  config: RateLimiterBuilder(a, b, c),
) -> Result(RateLimiter(a, b, c), String)

Build the rate limiter, but return an error instead of panicking.

Search Document