The state machine for workflow execution.
It tracks the progress of a Recipe, including which steps are pending, running, or completed, and holds the data (params) produced so far.
Data Structure Decisions
You might notice a mix of Lists and MapSets. This is intentional to balance deterministic execution with scheduling efficiency:
:pending_steps(List) - Kept as a list to preserve the definition order from the Recipe. When multiple steps are ready simultaneously, Orchid prefers to execute them in the order they were written. This ensures predictable behavior, especially for theSerialexecutor.:running_steps(MapSet) - Used for O(1) lookups. The scheduler frequently checksmember?/2inside loops; a MapSet prevents this from becoming a performance bottleneck.:available_keys(MapSet) - Optimized for Set Algebra. Dependency resolution relies heavily on subset checks (subset?/2), which MapSets handle efficiently.:recipe(Struct) - The Recipe being executed.:params(Map) - A map of parameters available in the current context.:history(List) - A list of tuples recording the execution history of steps, including their indices and output keys.:workflow_ctx(Struct) - TheOrchid.WorkflowCtxstruct associated with the execution.:assigns(Map) - A map for storing additional context-specific data.
Summary
Types
@type param_map() :: %{optional(atom() | binary()) => Orchid.Param.t()}
@type step_index() :: non_neg_integer()
@type t() :: %Orchid.Scheduler.Context{ assigns: %{required(any()) => any()}, available_keys: MapSet.t(Orchid.Step.io_key()), history: [{Orchid.Step.t(), MapSet.t(Orchid.Step.output_keys())}], params: param_map(), pending_steps: [{Orchid.Step.t(), step_index()}], recipe: Orchid.Recipe.t(), running_steps: MapSet.t(step_index()), workflow_ctx: Orchid.WorkflowCtx.t() }