Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-resilience

Resilience pipelines for Pudu: retry, circuit breaker, timeout, fallback, hedging, rate limiting, and chaos injection

0.1.0Apache-2.01

InstallClose

TokenBucket.pudu

Pudu43 lines2.0 KB

GitHub ↗
1/** @Limiter.TokenBucket.Module — permits drawn from a steadily refilled bucket */2module PuduLangResilience.Limiter.TokenBucket34import PuduLangResilience.Clock as Clock5import PuduLangResilience.Domain.Algorithms as Algorithms6import PuduLangResilience.Limiter.Engine as Engine7import PuduLangResilience.Limiter as Limiter89/** @Limiter.TokenBucket.Options — the bucket's size, refill, and queue */10export type Options = {11  tokenLimit: Int,12  tokensPerPeriod: Int,13  replenishmentPeriod: Int,14  autoReplenishment: Bool,15  queueLimit: Int,16  queueOrder: Limiter.QueueOrder,17  clock: Clock.Clock18}1920/// A full bucket of ten tokens gaining ten every second by itself, with no queue.21export fn defaults() -> Options {22  Options{tokenLimit: 10, tokensPerPeriod: 10, replenishmentPeriod: 1000, autoReplenishment: true, queueLimit: 0, queueOrder: Limiter.OldestFirst, clock: Clock.system()}23}2425/// Every reason the options cannot be followed.26export fn validate(options: &Options) -> Array[Str] {27  var problems: Array[Str] = []28  if options.tokenLimit < 1 { problems = problems.push("tokenLimit must be at least 1") }29  if options.tokensPerPeriod < 1 { problems = problems.push("tokensPerPeriod must be at least 1") }30  if options.replenishmentPeriod < 1 { problems = problems.push("replenishmentPeriod must be at least 1 ms") }31  if options.queueLimit < 0 { problems = problems.push("queueLimit must not be negative") }32  problems33}3435/// A token bucket limiter starting full, or every reason it cannot be made.36export fn create(options: &Options) -> Result[Limiter.Limiter, Array[Str]] {37  let problems = validate(options)38  if !problems.isEmpty() { return Err(problems) }39  let queueing = Engine.Queueing{permitLimit: options.tokenLimit, queueLimit: options.queueLimit, order: options.queueOrder}40  let start = Algorithms.Bucket{tokens: options.tokenLimit, stamp: Clock.now(&options.clock)}41  Ok(Engine.limiter(start, Algorithms.tokenBucket(options.tokenLimit, options.tokensPerPeriod, options.replenishmentPeriod, options.autoReplenishment), &queueing, options.clock))42}43