ExecutionPlan.ts
ExecutionPlan.ts overview
Section titled “ExecutionPlan.ts overview”Describes ordered fallback steps for running effects or streams.
An ExecutionPlan contains one or more steps. Each step provides a Context
or Layer, and may also define attempt limits, retry schedules, or
predicates that decide whether to keep trying. The runtime tries steps in
order until the workflow succeeds or the plan is exhausted. This module also
supports merging plans and reading metadata for the active step and attempt.
Since v3.16.0
Exports Grouped by Category
Section titled “Exports Grouped by Category”combining
Section titled “combining”Combines multiple execution plans by concatenating their steps in order.
When to use
Use to combine separately defined fallback plans into one ordered plan before applying it to an effect or stream.
Details
The resulting plan tries every step from the first plan, then every step from the next plan, and so on.
See
makefor building a plan from individual steps instead of combining existing plans
Signature
declare const merge: <const Plans extends NonEmptyReadonlyArray<ExecutionPlan<any>>>( ...plans: Plans) => ExecutionPlan<{ provides: make.PlanProvides<Plans> input: make.PlanInput<Plans> error: Plans[number] extends ExecutionPlan<infer T> ? T["error"] : never requirements: Plans[number] extends ExecutionPlan<infer T> ? T["requirements"] : never}>Since v3.16.0
constructors
Section titled “constructors”Create an ExecutionPlan, which can be used with Effect.withExecutionPlan or Stream.withExecutionPlan, allowing you to provide different resources for each step of execution until the effect succeeds or the plan is exhausted.
Example (Creating an execution plan)
import { Effect, ExecutionPlan, Schedule } from "effect"import type { Layer } from "effect"import type { LanguageModel } from "effect/unstable/ai"
declare const layerBad: Layer.Layer<LanguageModel.LanguageModel>declare const layerGood: Layer.Layer<LanguageModel.LanguageModel>
const ThePlan = ExecutionPlan.make( { // First try with the bad layer 2 times with a 3 second delay between attempts provide: layerBad, attempts: 2, schedule: Schedule.spaced(3000) }, // Then try with the bad layer 3 times with a 1 second delay between attempts { provide: layerBad, attempts: 3, schedule: Schedule.spaced(1000) }, // Finally try with the good layer. // // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided. { provide: layerGood })
declare const effect: Effect.Effect<void, never, LanguageModel.LanguageModel>const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)Signature
declare const make: <const Steps extends NonEmptyReadonlyArray<make.Step>>( ...steps: Steps & { [K in keyof Steps]: make.Step }) => ExecutionPlan<{ provides: make.StepProvides<Steps> input: make.StepInput<Steps> error: | (Steps[number]["provide"] extends Context.Context<infer _P> | Layer.Layer<infer _P, infer E, infer _R> ? E : never) | (Steps[number]["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer _R> ? _E : never) requirements: | (Steps[number]["provide"] extends Layer.Layer<infer _A, infer _E, infer R> ? R : never) | (Steps[number]["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer R> ? R : never) | (Steps[number]["schedule"] extends Schedule.Schedule<infer _O, infer _I, infer R> ? R : never)}>Since v3.16.0
guards
Section titled “guards”isExecutionPlan
Section titled “isExecutionPlan”Returns true if a value is an ExecutionPlan by checking for the
ExecutionPlan.TypeId marker.
When to use
Use when accepting an unknown value and you need to narrow it to an
ExecutionPlan before reading plan fields or passing it to plan-consuming
APIs.
Gotchas
This is a structural marker check; it does not validate the marker value or the shape of the plan steps.
See
makefor constructing execution plans that satisfy this guardTypeIdfor the runtime marker checked by this guard
Signature
declare const isExecutionPlan: (u: unknown) => u is ExecutionPlan<any>Since v3.16.0
metadata
Section titled “metadata”CurrentMetadata
Section titled “CurrentMetadata”Context reference containing metadata for the currently running execution-plan attempt.
When to use
Use to read the active plan step and attempt while code is running under an execution plan.
Signature
declare const CurrentMetadata: Context.Reference<Metadata>Since v4.0.0
Metadata (interface)
Section titled “Metadata (interface)”Metadata describing the currently running execution-plan attempt.
Details
attempt is the current 1-based attempt number, and stepIndex is the
0-based index of the plan step currently being evaluated.
Signature
export interface Metadata { readonly attempt: number readonly stepIndex: number}Since v4.0.0
models
Section titled “models”ConfigBase (type alias)
Section titled “ConfigBase (type alias)”Base type-level configuration carried by an ExecutionPlan.
Details
provides tracks services supplied by plan steps, input tracks the error
input consumed by schedules and while predicates, error tracks failures
from plan layers or predicates, and requirements tracks services needed to
build or run the plan.
Signature
type ConfigBase = { provides: any input: any error: any requirements: any}Since v4.0.0
ExecutionPlan (interface)
Section titled “ExecutionPlan (interface)”A ExecutionPlan can be used with Effect.withExecutionPlan or Stream.withExecutionPlan, allowing you to provide different resources for each step of execution until the effect succeeds or the plan is exhausted.
Example (Defining fallback execution steps)
import { Effect, ExecutionPlan, Schedule } from "effect"import type { Layer } from "effect"import type { LanguageModel } from "effect/unstable/ai"
declare const layerBad: Layer.Layer<LanguageModel.LanguageModel>declare const layerGood: Layer.Layer<LanguageModel.LanguageModel>
const ThePlan = ExecutionPlan.make( { // First try with the bad layer 2 times with a 3 second delay between attempts provide: layerBad, attempts: 2, schedule: Schedule.spaced(3000) }, // Then try with the bad layer 3 times with a 1 second delay between attempts { provide: layerBad, attempts: 3, schedule: Schedule.spaced(1000) }, // Finally try with the good layer. // // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided. { provide: layerGood })
declare const effect: Effect.Effect<void, never, LanguageModel.LanguageModel>const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)Signature
export interface ExecutionPlan< Config extends { provides: any input: any error: any requirements: any }> extends Pipeable { readonly [TypeId]: TypeId readonly steps: NonEmptyReadonlyArray<{ readonly provide: | Context.Context<Config["provides"]> | Layer.Layer<Config["provides"], Config["error"], Config["requirements"]> readonly attempts?: number | undefined readonly while?: | ((input: Config["input"]) => Effect.Effect<boolean, Config["error"], Config["requirements"]>) | undefined readonly schedule?: Schedule.Schedule<any, Config["input"], Config["requirements"]> | undefined }>
/** * Returns an equivalent `ExecutionPlan` with the requirements satisfied, using the current context. */ readonly captureRequirements: Effect.Effect< ExecutionPlan<{ provides: Config["provides"] input: Config["input"] error: Config["error"] requirements: never }>, never, Config["requirements"] >}Since v3.16.0
type IDs
Section titled “type IDs”TypeId
Section titled “TypeId”Runtime type identifier attached to ExecutionPlan values and used by
isExecutionPlan.
Signature
declare const TypeId: "~effect/ExecutionPlan"Since v3.16.0
TypeId (type alias)
Section titled “TypeId (type alias)”String literal type used as the runtime type identifier for ExecutionPlan
values.
Signature
type TypeId = "~effect/ExecutionPlan"Since v3.16.0
make (namespace)
Section titled “make (namespace)”Namespace containing type helpers used by ExecutionPlan.make.
Since v3.16.0
Step (type alias)
Section titled “Step (type alias)”Input shape for a single execution-plan step.
Details
Each step provides a Context or Layer and may limit attempts, add a
while predicate for retry decisions, or attach a Schedule for retry
timing.
Signature
type Step = { readonly provide: Context.Context<any> | Context.Context<never> | Layer.Any readonly attempts?: number | undefined readonly while?: ((input: any) => boolean | Effect.Effect<boolean, any, any>) | undefined readonly schedule?: Schedule.Schedule<any, any, any> | undefined}Since v3.16.0
StepProvides (type alias)
Section titled “StepProvides (type alias)”Computes the intersection of services provided by a list of execution-plan steps.
Signature
type StepProvides<Steps, Out> = Steps extends readonly [infer Step, ...infer Rest] ? StepProvides< Rest, Out & (Step extends { readonly provide: Context.Context<infer P> | Layer.Layer<infer P, infer _E, infer _R> } ? P : unknown) > : OutSince v3.16.1
PlanProvides (type alias)
Section titled “PlanProvides (type alias)”Computes the intersection of services provided by a list of execution plans.
Signature
type PlanProvides<Plans, Out> = Plans extends readonly [infer Plan, ...infer Rest] ? PlanProvides<Rest, Out & (Plan extends ExecutionPlan<infer T> ? T["provides"] : unknown)> : OutSince v3.16.1
StepInput (type alias)
Section titled “StepInput (type alias)”Computes the input type consumed by the while predicates and schedules in
a list of execution-plan steps.
Signature
type StepInput<Steps, Out> = Steps extends readonly [infer Step, ...infer Rest] ? StepInput< Rest, Out & ((Step extends { readonly while: (input: infer I) => infer _ } ? I : unknown) & (Step extends { readonly schedule: Schedule.Schedule<infer _O, infer I, infer _R> } ? I : unknown)) > : OutSince v3.16.0
PlanInput (type alias)
Section titled “PlanInput (type alias)”Computes the combined input type consumed by a list of execution plans.
Signature
type PlanInput<Plans, Out> = Plans extends readonly [infer Plan, ...infer Rest] ? PlanInput<Rest, Out & (Plan extends ExecutionPlan<infer T> ? T["input"] : unknown)> : OutSince v3.16.0