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

Outcome.pudu

Pudu64 lines2.8 KB

GitHub ↗
1/** @Chaos.Outcome.Strategy — answers a chosen outcome instead of running the callback */2module PuduLangResilience.Chaos.Outcome34import 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.Outcome.Injected — the outcome injected into one execution */12export type Injected[T, E] = { context: Context.Context, outcome: Resilience.Outcome[T, E] }1314/** @Chaos.Outcome.Options — which outcome to inject and how often */15export type Options[T, E] = {16  name: Option[Str],17  injection: Chaos.Injection,18  outcome: Option[Resilience.Outcome[T, E]],19  generator: Option[fn(Chaos.Arguments) -> Option[Resilience.Outcome[T, E]]],20  onInjected: Option[fn(Injected[T, E]) -> ()]21}2223/// The default injection with no outcome chosen yet.24export fn defaults[T, E]() -> Options[T, E] { Options{name: None, injection: Chaos.defaults(), outcome: None, generator: None, onInjected: None} }2526/// Injects `outcome` at the given injection settings.27export fn injecting[T, E](outcome: Resilience.Outcome[T, E], injection: Chaos.Injection) -> Options[T, E] {28  Options{..defaults(), injection: injection, outcome: Some(outcome)}29}3031/// Every reason the options cannot be followed.32export fn validate[T, E](options: &Options[T, E]) -> Array[Str] {33  var problems = Chaos.validate(&options.injection)34  if options.outcome == None && options.generator == None { problems = problems.push("an outcome or a generator is required") }35  problems36}3738/// An outcome injection strategy following the options. The generator is used when given; a39/// generator answering nothing injects nothing.40export fn strategy[T, E](options: Options[T, E]) -> Strategy.Strategy[T, E] {41  Strategy.Strategy {42    name: options.name,43    kind: "ChaosOutcome",44    summary: "injects an outcome 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.outcome52      }53      match chosen {54        case Some(outcome) => {55          Telemetry.report(&runtime.telemetry, &context, Events.ON_OUTCOME, Telemetry.Information, Some(Resilience.summarize(&outcome)), Telemetry.OutcomeInjected)56          if let Some(notify) = options.onInjected { notify(Injected{context: context, outcome: outcome}) }57          outcome58        }59        case None => callback(context)60      }61    }62  }63}64