Defines per-node scheduling policies for workflow execution.
A SchedulerPolicy controls retry behavior, timeouts, failure handling,
execution mode, and other scheduling concerns for individual workflow nodes.
Policies are resolved at runtime by matching against runnable nodes using
a list of {matcher, policy_map} tuples. The first matching rule wins,
and its policy map is merged over the default policy.
Matcher Types
atom()— exact match on the node's name:default— catch-all, always matches{:name, %Regex{}}— regex match on the node's name{:type, module}— match on the node's struct module{:type, [modules]}— match on any of the listed struct modulesfn/1— custom predicate function receiving the node
Backoff Strategies
:none— no delay between retries:linear—min(base_delay_ms * (attempt + 1), max_delay_ms):exponential—min(base_delay_ms * 2^attempt, max_delay_ms):jitter— randomized exponential:min(rand(base_delay_ms * 2^attempt), max_delay_ms)
Execution Modes
:sync— standard synchronous execution (default):async— asynchronous execution within the workflow's react cycle:durable— enables event emission (%RunnableDispatched{},%RunnableCompleted{},%RunnableFailed{}) for crash recovery and audit trails. Used byRunic.Runner.Workerto persist runnable lifecycle events in the workflow log.
Fallback Functions
When all retries are exhausted and a fallback function is set, it receives
(runnable, error) and must return one of:
%Runnable{}— a modified runnable to execute once (no further retries){:retry_with, %{key: value}}— overrides merged intometa_context, then executed once{:value, term}— a synthetic value used as the step's output
Any other return value causes the runnable to fail with {:invalid_fallback_return, value}.
Example
alias Runic.Workflow.SchedulerPolicy
policies = [
{:call_llm, %{max_retries: 3, backoff: :exponential, timeout_ms: 30_000}},
{{:type, Runic.Workflow.Step}, %{max_retries: 1, backoff: :linear}},
{:default, %{timeout_ms: 10_000}}
]
policy = SchedulerPolicy.resolve(runnable, policies)
Summary
Functions
Returns the default policy struct.
Policy preset for fast-fail scenarios: no retries, 5s timeout, halt on failure.
Policy preset for I/O-bound operations (HTTP, database, file system).
Policy preset for LLM / external AI model calls.
Merges two policy maps, with overrides taking precedence over base.
Merges runtime override policies with workflow base policies.
Creates a new SchedulerPolicy from a map or keyword list.
Resolves a SchedulerPolicy for a given runnable by walking a list of
{matcher, policy_map} tuples top-to-bottom. First match wins.
Types
@type fallback_fn() :: (Runic.Workflow.Runnable.t(), term() -> fallback_return()) | nil
@type fallback_return() :: Runic.Workflow.Runnable.t() | {:retry_with, map()} | {:value, term()}
@type t() :: %Runic.Workflow.SchedulerPolicy{ backoff: :none | :linear | :exponential | :jitter, base_delay_ms: non_neg_integer(), circuit_breaker: map() | nil, deadline_ms: non_neg_integer() | nil, execution_mode: :sync | :async | :durable, executor: module() | :inline | nil, executor_opts: keyword(), fallback: fallback_fn(), idempotency_key: term() | nil, max_delay_ms: non_neg_integer(), max_retries: non_neg_integer(), on_failure: :halt | :skip, priority: :low | :normal | :high | :critical, timeout_ms: non_neg_integer() | :infinity }
Functions
@spec default_policy() :: t()
Returns the default policy struct.
@spec fast_fail() :: t()
Policy preset for fast-fail scenarios: no retries, 5s timeout, halt on failure.
Policy preset for I/O-bound operations (HTTP, database, file system).
Defaults: 2 retries, linear backoff (500ms base), 10s timeout, skip on failure.
Override any default via opts.
Policy preset for LLM / external AI model calls.
Defaults: 3 retries, exponential backoff (1s base, 30s max), 30s timeout, halt on failure.
Override any default via opts.
Merges two policy maps, with overrides taking precedence over base.
Merges runtime override policies with workflow base policies.
In :merge mode (default), runtime overrides are prepended to the workflow base.
In :replace mode, only the runtime overrides are returned.
When runtime_overrides is nil or [], returns workflow_base unchanged.
Creates a new SchedulerPolicy from a map or keyword list.
Raises ArgumentError if any unknown keys are provided.
@spec resolve(Runic.Workflow.Runnable.t(), list() | nil) :: t()
Resolves a SchedulerPolicy for a given runnable by walking a list of
{matcher, policy_map} tuples top-to-bottom. First match wins.
The matched policy map is merged over the default policy. If no match is
found or policies is nil or [], returns the default policy.