Skip to main content
The store.Store interface is the single source of truth for all Aether state. It aggregates four sub-interfaces — WorkflowRunStore, TaskRunStore, SchemaStore, and CronWorkflowStore — into one type that is injected into the engine via WithStore(). Implementations define the persistence strategy: in-memory, SQL, Redis, or any other backend.
The engine uses a Token-based optimistic concurrency model. Every UpdateWorkflowRun and UpdateTaskRun call passes a Token opaque uint64. Implementations that enforce concurrency control compare this token against the stored value and return ErrTokenMismatch if they differ. Single-threaded stores may ignore the token entirely.

Store (aggregate interface)

Close() releases any resources held by the store (connections, goroutines, etc.).

WorkflowRunStore

Manages the lifecycle of workflow-level run records.
Stores the initial workflow run record. Called once at submit time with immutable data.
*WorkflowRun
required
The initial run record. RunID, Workflow (raw JSON), and CreatedAt are set by the engine.
Retrieves a workflow run by ID. Returns ErrNotFound if it does not exist.
string
required
The workflow run ID returned by Engine.Submit.
Persists mutable fields. Only non-nil pointer fields in the run argument are written; nil fields are left unchanged. Returns the post-update state on success.Uses Token-based optimistic locking — return ErrTokenMismatch on conflict.
Returns all non-terminal workflow runs that have a Deadline set. Used by the timeout watchdog.
Removes a workflow run and all its associated TaskRun records. Returns ErrNotFound if the run does not exist.
Returns all WorkflowRun records created by a given CronWorkflow. Used for concurrency policy checks and history cleanup.

TaskRunStore

Manages task run records within a workflow.
CreateTaskRun must be idempotent by the composite key (workflowRunID, parentRunID, scope, taskName). If a record with the same key already exists, implementations MUST return nil — not an error, not a duplicate. The engine relies on this for concurrent-safe scheduling.
Persists a new task run. Idempotent by composite key — repeated calls with the same key are a no-op. This is critical for loop scheduling where iterations share the same taskName but have unique Scope values.
Retrieves a single task run by its unique RunID.
Persists mutable fields using the nil-field partial update convention. Immutable fields (RunID, WorkflowRunID, ParentRunID, Scope, TaskName, etc.) are always ignored. Returns the post-update state on success.
Returns all task runs for a given workflow run, in creation order.
Returns task runs sharing the same parent container. parentRunID="" returns top-level tasks. This is the core query for scoped DAG scheduling — advanceScope uses it to find sibling tasks.
Returns all non-terminal task runs that have a Deadline set. Used by the timeout watchdog.

SchemaStore

Persists executor schemas for recovery after a master restart.
workerID="" in UpsertSchema marks a schema as an orphan (loaded during recovery). DeleteSchema accepts optional filters — empty string means no restriction on that dimension.

CronWorkflowStore

Manages CronWorkflow persistence.
DeleteCronWorkflow does NOT cascade-delete associated WorkflowRun records. ListCronWorkflows is called during Engine.Start() to re-register schedules after a crash.

Persistent model types

WorkflowRun

TaskRun

Error sentinels

error
Returned when a requested resource does not exist.
error
Returned when an Update call’s token does not match the stored token. Signals normal optimistic-lock contention — not an infrastructure failure. The engine treats this as a no-op for concurrent updates.

Inject with WithStore