
TokenBucket.pudu
Pudu43 lines2.0 KB
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}192021export fn defaults() -> Options {22 Options{tokenLimit: 10, tokensPerPeriod: 10, replenishmentPeriod: 1000, autoReplenishment: true, queueLimit: 0, queueOrder: Limiter.OldestFirst, clock: Clock.system()}23}242526export 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}343536export 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