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

Fallback.pudu

Pudu66 lines2.5 KB

GitHub ↗
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}1819/// Handles every failure except a cancellation; the action must still be given.20export fn defaults[T, E]() -> Options[T, E] {21  Options{name: None, shouldHandle: Predicate.failures(), action: None, onFallback: None}22}2324/// Answers `value` in place of every failure except a cancellation.25export 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}2829/// Every reason the options cannot be followed.30export 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}3637/// A fallback strategy following the options.38export 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}5051/// Runs the callback and, when the predicate handles its outcome, answers the action's outcome52/// for it instead.53fn 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