
SlidingWindow.pudu
Pudu45 lines2.1 KB
1/** @Limiter.SlidingWindow.Module — at most N permits in any moving window */2module PuduLangResilience.Limiter.SlidingWindow34import PuduLangResilience.Clock as Clock5import PuduLangResilience.Domain.Algorithms as Algorithms6import PuduLangResilience.Limiter.Engine as Engine7import PuduLangResilience.Limiter as Limiter89/** @Limiter.SlidingWindow.Options — permits per window, its segments, and the queue */10export type Options = {11 permitLimit: Int,12 window: Int,13 segmentsPerWindow: Int,14 autoReplenishment: Bool,15 queueLimit: Int,16 queueOrder: Limiter.QueueOrder,17 clock: Clock.Clock18}192021export fn defaults() -> Options {22 Options{permitLimit: 100, window: 1000, segmentsPerWindow: 10, 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.permitLimit < 1 { problems = problems.push("permitLimit must be at least 1") }29 if options.segmentsPerWindow < 1 { problems = problems.push("segmentsPerWindow must be at least 1") }30 if options.window < 1 || options.window < options.segmentsPerWindow { problems = problems.push("window must be at least 1 ms for each segment") }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.permitLimit, queueLimit: options.queueLimit, order: options.queueOrder}40 var counts: Array[Int] = []41 while counts.length() < options.segmentsPerWindow { counts = counts.push(0) }42 let start = Algorithms.Segments{counts: counts, start: Clock.now(&options.clock)}43 Ok(Engine.limiter(start, Algorithms.slidingWindow(options.permitLimit, options.window, options.segmentsPerWindow, options.autoReplenishment), &queueing, options.clock))44}45