Orchid.Step behaviour (Orchid v0.6.1)

Copy Markdown View Source

Defines the behavior and specification for a workflow step.

A Step is the atomic unit of work in Orchid. It is responsible for receiving data (wrapped in Orchid.Param), performing a specific task, and returning new data.

It focuses solely on processing logic, unaware of the larger workflow context.

Usage

To define a step, use Orchid.Step and implement the run/2 callback:

defmodule MySteps.Upcase do
  use Orchid.Step
  alias Orchid.Param

  @impl true
  def run(input_param, _opts) do
    payload = Param.get_payload(input_param)

    result =
      Param.new(:result, :string)
      |> Param.set_payload(String.upcase(payload))

    {:ok, result}
  end
end

Input Pattern Matching

The structure of the input argument in run/2 depends on how you define the input keys in your Recipe:

  • Single Key: If input is :my_data, run/2 receives a single %Param{}.
  • List of Keys: If input is [:a, :b], run/2 receives a list [%Param{}, %Param{}].
  • Tuple of Keys: If input is {:a, :b}, run/2 receives a tuple {%Param{}, %Param{}}.

Step Options

Options can be passed when defining the step in a recipe or injected dynamically. Reserved options include:

  • :extra_hooks_stack - A list of additional hooks to run for this specific step.
  • :__reporter_ctx__ - A map contains telemetry meta used by report/3 to send progress updates.

Summary

Types

The implementation of a step.

Options passed to the step execution context.

The schema definition of a step within a recipe. Format: {Implementation, InputKeys, OutputKeys}.

A fully qualified step definition including options. Format: {Implementation, InputKeys, OutputKeys, Options}.

t()

Callbacks

Determines if this step contains an inner recipe (Nested Step).

Executes the step logic.

Validates the options passed to the step before execution.

Functions

Normalizes a step structure into the full 4-element tuple format.

Extracts the basic schema {Impl, Input, Output} from a step definition.

Injects or merges options into a step definition.

Reports progress or status to the executor.

Types

implementation()

@type implementation() :: module() | function() | nil

The implementation of a step.

  • module(): A module that implements the Orchid.Step behavior.
  • function(): A function fn input, opts -> {:ok, params} | {:error, term} end.

input()

@type input() :: tuple() | Orchid.Param.t() | [Orchid.Param.t()]

input_keys()

@type input_keys() :: io_key()

io_key()

@type io_key() ::
  atom()
  | binary()
  | [atom()]
  | [binary()]
  | tuple()
  | MapSet.t(atom())
  | MapSet.t(binary())

output()

@type output() :: tuple() | Orchid.Param.t() | [Orchid.Param.t()]

output_keys()

@type output_keys() :: io_key()

step_options()

@type step_options() :: keyword()

Options passed to the step execution context.

step_schema()

@type step_schema() :: {implementation(), input_keys(), output_keys()}

The schema definition of a step within a recipe. Format: {Implementation, InputKeys, OutputKeys}.

step_with_options()

@type step_with_options() ::
  {implementation(), input_keys(), output_keys(), step_options()}

A fully qualified step definition including options. Format: {Implementation, InputKeys, OutputKeys, Options}.

t()

@type t() :: step_schema() | step_with_options()

Callbacks

nested?()

@callback nested?() :: boolean()

Determines if this step contains an inner recipe (Nested Step).

run(input, step_options)

@callback run(input(), step_options()) :: {:ok, output()} | {:error, term()}

Executes the step logic.

Arguments

  • input - The input parameters. Structure depends on input_keys definition.
  • opts - The keyword list of options available to this step.

Return Values

  • {:ok, output} - Execution succeeded. output must match the structure of output_keys.
  • {:error, reason} - Execution failed. The step (and potentially the workflow) halts.

validate_options(step_options)

@callback validate_options(step_options()) :: :ok | {:error, term()}

Validates the options passed to the step before execution.

This is useful for checking required configuration keys (e.g., API tokens, thresholds). Returns :ok if valid, or {:error, reason} otherwise.

Functions

ensure_full_step(arg)

@spec ensure_full_step(t()) :: step_with_options()

Normalizes a step structure into the full 4-element tuple format.

extract_schema(arg)

@spec extract_schema(t()) :: step_schema()

Extracts the basic schema {Impl, Input, Output} from a step definition.

inject_options(step, options)

@spec inject_options(
  t(),
  keyword()
) :: step_with_options()

Injects or merges options into a step definition.

Supports both 3-element tuple (Schema) and 4-element tuple (Full Step).

report(opts, progress, payload \\ nil)

@spec report(keyword(), term(), term()) :: :ok

Reports progress or status to the executor.

Example

def run(input, opts) do
  report(opts, :processing, "Start heavy calculation...")
  # ...
  report(opts, :uploading, 50)
  {:ok, result}
end