glimit/bucket

This module contains pure token-bucket functions used by the rate limiter.

Types

The state of a single token bucket.

pub type BucketState {
  BucketState(
    max_token_count: Int,
    token_rate: Int,
    token_count: Float,
    last_update: option.Option(Int),
  )
}

Constructors

  • BucketState(
      max_token_count: Int,
      token_rate: Int,
      token_count: Float,
      last_update: option.Option(Int),
    )

    Arguments

    max_token_count

    The maximum number of tokens.

    token_rate

    The rate of token generation per second.

    token_count

    The number of tokens available.

    last_update

    Monotonic timestamp (milliseconds) of the last time the bucket was updated.

A pluggable storage backend for distributed rate limiting.

All token bucket logic is handled by glimit — store adapters only need to implement simple lock-and-get / set-and-unlock operations on string-keyed bucket state.

  • lock_and_get: Acquire an exclusive lock for the key and retrieve its bucket state. Return Ok(None) for a new/missing key. If the lock cannot be acquired, return Error(Nil).
  • set_and_unlock: Persist bucket state with a TTL in seconds for automatic expiry, then release the lock.
  • unlock: Release the lock without writing. Used on error paths when there is nothing to persist.

When lock_and_get fails, the rate limiter fails open (allows the request).

pub type Store {
  Store(
    lock_and_get: fn(String) -> Result(
      option.Option(BucketState),
      Nil,
    ),
    set_and_unlock: fn(String, BucketState, Int) -> Result(
      Nil,
      Nil,
    ),
    unlock: fn(String) -> Result(Nil, Nil),
  )
}

Constructors

  • Store(
      lock_and_get: fn(String) -> Result(
        option.Option(BucketState),
        Nil,
      ),
      set_and_unlock: fn(String, BucketState, Int) -> Result(Nil, Nil),
      unlock: fn(String) -> Result(Nil, Nil),
    )

Values

pub fn compute_ttl(b: BucketState) -> Int

Compute a TTL in seconds for the bucket state.

The TTL is based on the time it takes to fully refill from empty, with a minimum of 60 seconds.

pub fn from_pairs(
  pairs: List(#(String, String)),
) -> Result(BucketState, Nil)

Parse a BucketState from a list of string key-value pairs.

This is the inverse of to_pairs. Returns Error(Nil) if any required field is missing or cannot be parsed.

pub fn hit(
  state: BucketState,
  now: Int,
) -> #(Result(Nil, Nil), BucketState)

Hit the bucket: refill, then try to consume one token.

Returns #(Ok(Nil), new_state) on success, #(Error(Nil), new_state) when rate-limited.

pub fn is_full(state: BucketState, now: Int) -> Bool

Returns True if the bucket is full after refilling.

pub fn new(
  max_token_count: Int,
  token_rate: Int,
) -> Result(BucketState, Nil)

Create a new bucket state.

Returns Error(Nil) if max_token_count or token_rate are not positive.

pub fn refill(state: BucketState, now: Int) -> BucketState

Refill the bucket based on elapsed time.

pub fn to_pairs(state: BucketState) -> List(#(String, String))

Convert a BucketState to a list of string key-value pairs.

Useful for serializing bucket state into external stores (e.g. Redis HSET). Keys: "tc" (token count), "lu" (last update), "mt" (max tokens), "tr" (token rate).

Search Document