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

SlidingWindow.pudu

Pudu45 lines2.1 KB

GitHub ↗
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}1920/// A hundred permits in any second, counted in ten segments, with no queue.21export fn defaults() -> Options {22  Options{permitLimit: 100, window: 1000, segmentsPerWindow: 10, 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.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}3435/// A sliding window limiter whose first segment starts now, 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.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