Current section
Files
Jump to
Current section
Files
lib/orchid.ex
defmodule Orchid do
@moduledoc """
The core entry point for the Orchid workflow engine.
This module provides the primary interface (`run/3`) to execute defined Recipes.
It is designed to be a flexible and extensible framework for task orchestration.
"""
alias Orchid.{Recipe, Step, Pipeline, Scheduler, WorkflowCtx}
alias Orchid.Operon.{Request, Response, Execute}
@allow_config_keys [
:return_response,
:operons_stack,
:global_hooks_stack,
:executor_and_opts,
:core_hook
]
@doc """
Executes a workflow Recipe.
It initializes the pipeline, injects any configured middleware (Operons), and
starts the execution process.
### Options
* `:return_response` - (boolean) If `true`, returns the full `Orchid.Operon.Response` struct
(which includes assigns and metadata) instead of just the result payload. Defaults to `false`.
* `:operons_stack` - (list) A list of additional middleware modules (Recipe-level hooks)
to run before the execution phase. They are executed in the order provided.
* `:global_hooks_stack` - (list)
* `:executor_and_opts` - (tuple) Executor module and its options.
* `:core_hook` - (module) A Module for execute step.
* `:baggage` - (enumerable) Custom options used by user/custome operons/hooks/etc.
### Examples
# Normal execution returning {:ok, results}
Orchid.run(my_recipe, initial_params)
# Execution returning the full Response struct
Orchid.run(my_recipe, initial_params, return_response: true)
"""
@spec run(Recipe.t() | [Step.t()], Scheduler.initial_params(), keyword()) ::
Response.payload() | Response.t()
def run(recipe_or_steps, input_params, opts \\ []) do
initial_config = Keyword.filter(opts, fn {k, _v} -> k in @allow_config_keys end)
ctx =
WorkflowCtx.new()
|> WorkflowCtx.merge_config(initial_config)
|> WorkflowCtx.merge_baggage(Keyword.get(opts, :baggage, []))
run_with_ctx(recipe_or_steps, input_params, ctx)
end
@doc "Run with explicit WorkflowContext struct."
@spec run_with_ctx(Recipe.t() | [Step.t()], Scheduler.initial_params(), WorkflowCtx.t()) ::
Response.payload() | Response.t()
def run_with_ctx(steps, input_params, workflow_ctx) when is_list(steps) do
run_with_ctx(Recipe.new(steps), input_params, workflow_ctx)
end
def run_with_ctx(recipe, input_params, workflow_ctx) do
response? = WorkflowCtx.get_config(workflow_ctx, :return_response, false)
operons_stack = WorkflowCtx.get_config(workflow_ctx, :operons_stack, [])
initial_request = %Request{
recipe: recipe,
initial_params: input_params,
workflow_ctx: workflow_ctx
}
response = Pipeline.run(operons_stack ++ [Execute], initial_request)
if response?, do: response, else: response.payload
end
end