
Fault.pudu
Pudu64 lines2.7 KB
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}222324export fn defaults[E]() -> Options[E] { Options{name: None, injection: Chaos.defaults(), fault: None, generator: None, onInjected: None} }252627export fn injecting[E](failure: Resilience.Failure[E], injection: Chaos.Injection) -> Options[E] {28 Options{..defaults(), injection: injection, fault: Some(failure)}29}303132export 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}37383940export 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