
Fallback.pudu
Pudu66 lines2.5 KB
1/** @Resilience.Fallback.Strategy — substitutes an outcome for a handled one */2module PuduLangResilience.Fallback34import PuduLangResilience.Constants.Events as Events5import PuduLangResilience.Context as Context6import PuduLangResilience.Predicate as Predicate7import PuduLangResilience as Resilience8import PuduLangResilience.Strategy as Strategy9import PuduLangResilience.Telemetry as Telemetry1011/** @Resilience.Fallback.Options — what to handle and what to answer instead */12export type Options[T, E] = {13 name: Option[Str],14 shouldHandle: Predicate.Predicate[T, E],15 action: Option[fn(Predicate.Arguments[T, E]) -> Resilience.Outcome[T, E]],16 onFallback: Option[fn(Predicate.Arguments[T, E]) -> ()]17}181920export fn defaults[T, E]() -> Options[T, E] {21 Options{name: None, shouldHandle: Predicate.failures(), action: None, onFallback: None}22}232425export fn withValue[T, E](value: T) -> Options[T, E] {26 Options{..defaults(), action: Some(fn(_given: Predicate.Arguments[T, E]) -> Resilience.Outcome[T, E] { Ok(value) })}27}282930export fn validate[T, E](options: &Options[T, E]) -> Array[Str] {31 match options.action {32 case Some(_) => []33 case None => ["action is required"]34 }35}363738export fn strategy[T, E](options: Options[T, E]) -> Strategy.Strategy[T, E] {39 Strategy.Strategy {40 name: options.name,41 kind: "Fallback",42 summary: "fallback",43 problems: validate(&options),44 attach: Strategy.detached,45 execute: fn(runtime: Strategy.Runtime, context: Context.Context, callback: Strategy.Callback[T, E]) -> Resilience.Outcome[T, E] {46 execute(&options, &runtime, context, callback)47 }48 }49}50515253fn execute[T, E](options: &Options[T, E], runtime: &Strategy.Runtime, context: Context.Context, callback: Strategy.Callback[T, E]) -> Resilience.Outcome[T, E] {54 let outcome = callback(context)55 let given = Predicate.arguments(outcome, context, 0)56 if !(options.shouldHandle)(given) { return outcome }57 match options.action {58 case Some(substitute) => {59 Telemetry.report(&runtime.telemetry, &context, Events.ON_FALLBACK, Telemetry.Warning, Some(Resilience.summarize(&outcome)), Telemetry.FellBack)60 if let Some(notify) = options.onFallback { notify(given) }61 substitute(given)62 }63 case None => outcome64 }65}66