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

Fault.pudu

Pudu64 lines2.7 KB

GitHub ↗
1/** @Chaos.Fault.Strategy — answers a failure instead of running the callback */2module PuduLangResilience.Chaos.Fault34import PuduLangResilience.Chaos as Chaos5import PuduLangResilience.Constants.Events as Events6import PuduLangResilience.Context as Context7import PuduLangResilience as Resilience8import PuduLangResilience.Strategy as Strategy9import PuduLangResilience.Telemetry as Telemetry1011/** @Chaos.Fault.Injected — the failure injected into one execution */12export type Injected[E] = { context: Context.Context, failure: Resilience.Failure[E] }1314/** @Chaos.Fault.Options — which failure to inject and how often */15export type Options[E] = {16  name: Option[Str],17  injection: Chaos.Injection,18  fault: Option[Resilience.Failure[E]],19  generator: Option[fn(Chaos.Arguments) -> Option[Resilience.Failure[E]]],20  onInjected: Option[fn(Injected[E]) -> ()]21}2223/// The default injection with no failure chosen yet.24export fn defaults[E]() -> Options[E] { Options{name: None, injection: Chaos.defaults(), fault: None, generator: None, onInjected: None} }2526/// Injects `failure` at the given injection settings.27export fn injecting[E](failure: Resilience.Failure[E], injection: Chaos.Injection) -> Options[E] {28  Options{..defaults(), injection: injection, fault: Some(failure)}29}3031/// Every reason the options cannot be followed.32export fn validate[E](options: &Options[E]) -> Array[Str] {33  var problems = Chaos.validate(&options.injection)34  if options.fault == None && options.generator == None { problems = problems.push("a fault or a generator is required") }35  problems36}3738/// A fault injection strategy following the options. The generator is used when given; a39/// generator answering nothing injects nothing.40export fn strategy[T, E](options: Options[E]) -> Strategy.Strategy[T, E] {41  Strategy.Strategy {42    name: options.name,43    kind: "ChaosFault",44    summary: "injects a fault at rate " + show(options.injection.rate),45    problems: validate(&options),46    attach: Strategy.detached,47    execute: fn(runtime: Strategy.Runtime, context: Context.Context, callback: Strategy.Callback[T, E]) -> Resilience.Outcome[T, E] {48      if !Chaos.shouldInject(&options.injection, &context, &runtime.randomizer) { return callback(context) }49      let chosen = match options.generator {50        case Some(generate) => generate(Chaos.arguments(&context, &runtime.randomizer))51        case None => options.fault52      }53      match chosen {54        case Some(failure) => {55          Telemetry.report(&runtime.telemetry, &context, Events.ON_FAULT, Telemetry.Information, Some(Resilience.describe(&failure)), Telemetry.FaultInjected)56          if let Some(notify) = options.onInjected { notify(Injected{context: context, failure: failure}) }57          Err(failure)58        }59        case None => callback(context)60      }61    }62  }63}64