crabbucket/pgo

Types

pub type RemainingTokenCountFailure {
  MustWaitUntil(next_reset_timestamp: Int)
  PgoError(error: pgo.QueryError)
}

Constructors

  • MustWaitUntil(next_reset_timestamp: Int)
  • PgoError(error: pgo.QueryError)
pub type RemainingTokenCountSuccess {
  HasRemainingTokens(
    remaining_tokens: Int,
    next_reset_timestamp: Int,
  )
}

Constructors

  • HasRemainingTokens(
      remaining_tokens: Int,
      next_reset_timestamp: Int,
    )
pub type TokenBucketCleanerMessage(msg) {
  ShutdownTokenBucketCleaner
  StartTokenBucketCleaner(
    Subject(TokenBucketCleanerMessage(msg)),
  )
  RunTokenBucketCleaner(Subject(TokenBucketCleanerMessage(msg)))
}

Constructors

  • ShutdownTokenBucketCleaner
  • StartTokenBucketCleaner(Subject(TokenBucketCleanerMessage(msg)))
  • RunTokenBucketCleaner(Subject(TokenBucketCleanerMessage(msg)))
pub type TokenBucketCleanerState(key) {
  TokenBucketCleanerState(
    conn: Connection,
    sweep_interval_ms: Int,
  )
}

Constructors

  • TokenBucketCleanerState(conn: Connection, sweep_interval_ms: Int)

Constants

pub const index_migration_sql: String
pub const schema_migration_sql: String
pub const table_migration_sql: String

Functions

pub fn create_and_start_cleaner(
  conn: Connection,
  sweep_interval_ms: Int,
) -> Subject(TokenBucketCleanerMessage(a))

Having our token buckets in a database table means there’s going to be cruft left behind. To mitigate this, a TokenBucketCleaner is an actor which periodically executes a SQL command to purge expired buckets.

sweep_interval_ms describes how often the script should run, in milliseconds.

The cleaner deletes 1,000-record segments at a time to help avoid writer contention in the database, and is hard-coded to only delete up to 10 segments (10,000 records) at a time, to avoid holding onto a pool connection for too long.

pub fn handle_cleaner_message(
  message: TokenBucketCleanerMessage(a),
  state: TokenBucketCleanerState(b),
) -> Next(
  TokenBucketCleanerMessage(a),
  TokenBucketCleanerState(b),
)
pub fn remaining_tokens_for_key(
  conn: Connection,
  key: String,
  window_duration_ms: Int,
  default_tokens: Int,
) -> Result(
  RemainingTokenCountSuccess,
  RemainingTokenCountFailure,
)

Takes an arbitrary key and window duration, inserting a record if non-existing.

Suggestion: you may wish to format your key such that it indicates usage / purpose, value type, and value. For instance, if you’re limiting a specific endpoint for a given user, the key might look something like: some_endpoint_name:user:12345

window_duration_milliseconds describes the length of the time window valid for a number of tokens. For instance, a value of 1,000 with a default token count of 100 would mean an action could occur 100 times per second.

Return should be either HasRemainingTokens(remaining_tokens: Int, next_reset_timestamp: Int), which indicates that an action may proceed and contains how many more times the action may occur with the current window, or it may be MustWaitUntil(next_reset_timestamp: Int), which indicates that no tokens remain for this key and the next Unix timestamp (in milliseconds) that the client must wait for.

Search Document