Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

ExecutionPlan unstable

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.

14 exports Since v3.16.0 Source

Combining

merge

unstable
Since v3.16.0

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

  • make for building a plan from individual steps instead of combining existing plans

Signature

declare function merge<Plans extends readonly [ExecutionPlan<any>, ExecutionPlan<any>]>(...plans: Plans): ExecutionPlan<{
error: Plans[number] extends ExecutionPlan<T> ? T["error"] : never;
input: PlanInput<Plans>;
provides: PlanProvides<Plans>;
requirements: Plans[number] extends ExecutionPlan<T> ? T["requirements"] : never;
}>

Constructors

make

unstable
Since v3.16.0

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.

Signature

declare function make<Steps extends readonly [Step, Step]>(...steps: Steps & { [K in string | number | symbol]: Step }): ExecutionPlan<{
error: StepError<Steps[number]>;
input: StepInput<Steps>;
provides: StepProvides<Steps>;
requirements: StepRequirements<Steps[number]>;
}>

Example Creating an execution plan

import { Context, ExecutionPlan } from "effect"
const ThePlan = ExecutionPlan.make(
{
provide: Context.empty(),
attempts: 2
},
{
provide: Context.empty()
}
)
ThePlan.steps.length // => 2

Guards

Since v3.16.0

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

  • make for constructing execution plans that satisfy this guard
  • TypeId for the runtime marker checked by this guard

Signature

declare function isExecutionPlan(u: unknown): u is ExecutionPlan<any>

Metadata

Metadata

interface unstable
Since v4.0.0

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

interface Metadata {
readonly attempt: number;
readonly stepIndex: number;
}

Models

AttemptFailure

interface unstable
Since v4.0.0

Lifecycle event emitted when an execution-plan attempt fails.

Details

cause holds the full failure cause, so defects and interruption are reported as well as expected errors. Whether the plan retries or fails over afterwards is decided by the step's attempts, while, and schedule; a following AttemptStart indicates another attempt was made.

Signature

interface AttemptFailure<E> {
readonly _tag: "AttemptFailure";
readonly attempt: number;
readonly cause: Cause<E>;
readonly duration: Duration;
readonly stepAttempt: number;
readonly stepIndex: number;
}

AttemptStart

interface unstable
Since v4.0.0

Lifecycle event emitted before an execution-plan attempt runs.

Details

attempt is the cumulative 1-based attempt number across all steps and matches CurrentMetadata.attempt for the same attempt. stepAttempt is the 1-based attempt number within the current step, and stepIndex is the 0-based index of the step being attempted.

Signature

interface AttemptStart {
readonly _tag: "AttemptStart";
readonly attempt: number;
readonly stepAttempt: number;
readonly stepIndex: number;
}

AttemptSuccess

interface unstable
Since v4.0.0

Lifecycle event emitted when an execution-plan attempt succeeds.

Details

A successful attempt completes the plan, so this is always the final event. duration is the elapsed time of the attempt.

Signature

interface AttemptSuccess {
readonly _tag: "AttemptSuccess";
readonly attempt: number;
readonly duration: Duration;
readonly stepAttempt: number;
readonly stepIndex: number;
}

ConfigBase

type unstable
Since v4.0.0

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, predicates, or schedules, and requirements tracks services needed to build or run the plan.

Signature

type ConfigBase = {
error: any;
input: any;
provides: any;
requirements: any;
}

Event

type unstable
Since v4.0.0

Union of the lifecycle events emitted while an execution plan runs.

Details

Every AttemptStart is followed by exactly one terminal event, either AttemptSuccess or AttemptFailure. An interrupted attempt emits AttemptFailure with the interruption cause.

Signature

type Event<E> = AttemptStart | AttemptSuccess | AttemptFailure<E>

ExecutionPlan

interface unstable
Since v3.16.0

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.

Signature

interface ExecutionPlan<Config extends {
error: any;
input: any;
provides: any;
requirements: any;
}> extends Pipeable {
readonly "~effect/ExecutionPlan": "~effect/ExecutionPlan";
readonly captureRequirements: Effect<ExecutionPlan<{
error: Config["error"];
input: Config["input"];
provides: Config["provides"];
requirements: never;
}>, never, Config["requirements"]>;
readonly steps: readonly [{
readonly attempts?: number;
readonly provide: Context<Config["provides"]> | Layer<Config["provides"], Config["error"], Config["requirements"]>;
readonly schedule?: Schedule<any, Config["input"], Config["error"], Config["requirements"]>;
readonly while?: (input: Config["input"]) => Effect<boolean, Config["error"], Config["requirements"]>;
}, {
readonly attempts?: number;
readonly provide: Context<Config["provides"]> | Layer<Config["provides"], Config["error"], Config["requirements"]>;
readonly schedule?: Schedule<any, Config["input"], Config["error"], Config["requirements"]>;
readonly while?: (input: Config["input"]) => Effect<boolean, Config["error"], Config["requirements"]>;
}];
}

Example Defining fallback execution steps

import { Context, ExecutionPlan } from "effect"
const ThePlan = ExecutionPlan.make(
{
provide: Context.empty(),
attempts: 2
},
{
provide: Context.empty()
}
)
ThePlan.steps.map((step) => step.attempts ?? 1) // => [2, 1]

Other

make

unstable
Since v3.16.0

Namespace containing type helpers used by ExecutionPlan.make.

Services

Since v4.0.0

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: Reference<Metadata>

Type IDs

TypeId

unstable
Since v3.16.0

Runtime type identifier attached to ExecutionPlan values and used by isExecutionPlan.

Signature

declare const TypeId: "~effect/ExecutionPlan"

TypeId

type unstable
Since v3.16.0

String literal type used as the runtime type identifier for ExecutionPlan values.

Signature

type TypeId = "~effect/ExecutionPlan"