All operations reserve deterministic IDs in call order. Replaying the same history with a changed type, subtype, name, or parent fails before user code is executed.
step isolates nondeterministic work. A successful checkpoint returns the
deserialized historical result without rerunning the callable.
at_least_once_per_retrymay rerun an interrupted attempt.at_most_once_per_retryschedules a new retry or fails rather than rerunning an interrupted attempt.
wait writes a timer checkpoint and suspends. It returns only after replay
observes SUCCEEDED.
create_callback<Result> writes a callback checkpoint and returns
callback_handle<Result>. Creation only validates that callback details and an
ID exist. Terminal callback errors are intentionally deferred until
callback_handle::result() so code between creation and result retrieval runs
on both original execution and replay.
result() returns std::optional<Result>:
- a payload produces a value through the selected serializer;
- successful completion without a payload produces
std::nullopt; - incomplete callbacks suspend;
- failed, cancelled, timed-out, or stopped callbacks throw
callback_error.
The default string callback serializer is pass-through because callback success APIs already provide a serialized string payload. Supply a serializer for typed results.
wait_for_callback creates a non-virtual child context containing:
- a callback operation;
- a durable submitter step;
- callback result retrieval.
The submitter accepts std::string_view callback_id or no arguments. Passing
the ID directly is explicit, testable, and avoids an additional thread-local
context API.
invoke<Result> serializes its payload, starts a CHAINED_INVOKE, and suspends.
On replay it returns std::optional<Result>, or throws callable_error for a
terminal failure. A function name or ARN and optional tenant ID are recorded in
the start checkpoint.
run_in_child_context creates a CONTEXT operation and executes nested durable
operations in a namespace prefixed by the child operation ID. This prevents
collisions between identical child workflows.
Results up to 256 KiB are checkpointed normally. Larger results set
ReplayChildren; an optional summary generator supplies the compact checkpoint
payload, and replay re-executes the child operations to reconstruct the full
result.
Virtual contexts use the same prefixed ID namespace but omit context lifecycle checkpoints. Their child operations are flattened under the current parent. Changing an observable context between virtual and non-virtual mode fails closed when prior history makes the mismatch detectable.
parallel accepts either a random-access range of homogeneous callables or a
tuple of heterogeneous callable types with a common result type. Branch IDs are
reserved on the caller thread before any worker starts, so scheduling order
cannot change durable history identities.
Each nested branch has subtype ParallelBranch. Flat nesting omits branch
context lifecycle checkpoints while retaining its prefixed ID namespace.
batch_result records successful, failed, cancelled, and still-started items.
map copies the input range into stable storage, reserves one deterministic
MapIteration branch per item, and invokes the item function through the same
parallel executor. max_concurrency limits worker slots.
completion_config supports:
- minimum successful count;
- tolerated failure count;
- first successful;
- all successful/all completed;
- a deterministic custom decision callback.
Early completion prevents unscheduled branches from starting and records them as cancelled. Synchronous C++ code already running on another worker cannot be forcibly interrupted safely, so workers already executing are joined before the aggregate result is returned.
wait_for_condition<State> stores the latest state in the STEP retry payload.
The check receives optional current state and optionally the one-based attempt.
A polling strategy returns the next delay or std::nullopt to complete.
Pending checkpoints suspend without running the check. READY checkpoints restore state, increment the attempt, and execute the next check. Exhaustion and checker exceptions are checkpointed as terminal failures.
with_retry wraps an entire durable block in a child context. The body accepts
the one-based attempt or no arguments. A failed attempt creates a named durable
wait before reconstructing the next attempt during replay.
Durable suspension, checkpoint failures, state-fetch failures, serialization
errors, and replay-identity errors are control failures and are not treated as
retryable body errors. Applications can supply retry_decider to filter other
exceptions.
The replay_safe namespace provides checkpointed:
- uniform random doubles;
- millisecond-normalized UTC
timestampvalues; - Unix timestamps in seconds;
- RFC 4122 version-4
uuid_valuevalues.
Each helper is a normal durable step, so replay returns exactly the checkpointed value without calling the clock or entropy source again.
recurse and recurse_json build on chained invoke. The target is resolved
from an explicit function name or Lambda invocation metadata. Unqualified
runtime names are combined with the function version when available.
Recursive payloads must differ from the current execution input.
with_recursive_level requires a JSON object and replaces
__recursive_level with the current level plus one. Tenant metadata is
propagated unless explicitly overridden.
flow_builder creates typed node handles without executing user code. Calling
flow freezes and validates the definition before writing the top-level
checkpoint.
Validation rejects:
- blank or duplicate node names;
- self and duplicate dependencies;
- nodes or outputs from another builder;
- cycles;
- mutation after freeze.
Only nodes reachable by reverse dependency traversal from selected outputs are executed. Other nodes appear as skipped without consuming operation IDs.
Dependencies are immutable expressions:
node.succeeded()requires a successful result;node.failed()routes failure and marks it handled;node.completed()matches every settled logical status without handling a failure;&&requires every child expression;||requires one child expression.
ANY expressions choose the first matching child in expression order from the currently settled durable results. This deterministic rule avoids completion-order drift between native threads and replay.
Ready nodes execute concurrently in pre-reserved child contexts. Node callables
receive flow_node_context& or no arguments. The context provides typed,
freshly deserialized snapshots of direct dependency outcomes, results, and
errors, preventing mutable values from leaking between consumers.
Logical node exceptions become flow_node_status::failed records and can
activate failure routes. Durable suspension and SDK control failures propagate
without being misclassified as logical failures.
flow_result supports typed node lookup and selected outcome, error, or full
result projections. Unhandled failures and unavailable outcome projections
raise flow_execution_error only after the complete flow result has been
checkpointed.