When to use it
Use restart and retry when a run failed and you want to re-run part of it without repeating earlier work. Use resume after the server stopped in the middle of runs: they are markedABORTED at the next start, and you can continue them from their checkpoints.
What a checkpoint is
Every message a node emits is recorded, in order, as it leaves the node. When the node completes normally, a small durable end marker is written and forced to disk before downstream nodes see the node’s completion. A node counts as finished only when its marker exists. A resume trusts only that marker. It does not trust the execution log to say that a node finished, because the log record of a node end may still have been waiting to be written when the server stopped. If a checkpoint cannot be saved, or the marker cannot be written, the run carries on. The node is left unmarked, so a resume runs it again instead of trusting a partial output. The counteryukta.checkpoint.errors counts failed markers.
Where checkpoints are kept
In-memory caps
A node that goes over a cap is marked incomplete. A restart that needs its output is refused instead of replaying part of it, unless a spill directory is set. Do not point the spill directory at a folder shared with another process. Leftover spill files from an earlier process are removed at start.
Messages come back from files and from PostgreSQL as plain JSON values. A resume reads a node’s whole output into memory.
See Persistence for the file layout and PostgreSQL tables.
Restart, restart from a node, retry a node
These three operations start a new execution, with a new execution id, from a finished or running one.
Rules:
- The execution must still be in the in-memory archive: the newest
yukta.restart.retained-executionsexecutions, running or finished. Otherwise the server answers404with “no longer restartable”. - After a server restart the archive is empty, so restart and restart from a node are not available for earlier runs. Use resume for runs that a restart aborted.
- On a run that is still going, only parents that have finished (they have their end marker) are replayed. If a parent is still producing output, the request is refused with
400. - A parent whose output went over the in-memory caps makes the request fail with
400, unless the output is on disk or in PostgreSQL. - Retry on a node that did not fail is refused with
400. - A restart takes a slot like any start. It can wait with status
QUEUEDor be refused with429. - A second restart of the same execution while one is in progress is refused.
Recovery on boot
When the server starts with a durable execution log, it reads the log and:- Marks every run that has a start and no end as
ABORTED. - Restores the newest
yukta.execution-log.retained-runsruns into history. - Drops older runs from the log and deletes their checkpoints.
- Re-applies the newest scheduler limit change recorded in the log.
Resume
Resume continues a run that a restart aborted, as a new run. Nodes that finished are not run again. Their recorded output is replayed to the nodes that did not finish, and those run.Conditions
- A durable execution log (
yukta.execution-log.diror PostgreSQL), because the log holds the start payload. - A file or PostgreSQL checkpoint store, because only a durable end marker counts as finished.
- The run is
ABORTED. - The workflow definition is unchanged since the run started.
- A run is resumed once.
Refusals
Auto-resume
Withyukta.restart.auto-resume=true, after each recovery the server resumes every interrupted run, one after another. A run that cannot be resumed is logged and skipped. Auto-resume is off by default.
Approvals
An answered approval (a signal sent to aWAIT_FOR_SIGNAL node) is recorded with the checkpoints. A resumed run reuses the answer for the same message instead of waiting again. An approval that timed out is not recorded. A wait that was still open when the server stopped is lost, and the resumed run waits for a new signal.
Make plugin side effects safe to repeat
Delivery is at-least-once. There is a short moment between a plugin acting on the outside world and its node’s end marker reaching disk. If the server stops in that moment, a resume runs the node again. Retries repeat per message, and a resume can repeat a node. Make side effects idempotent:- Use the stable message id (and the
attemptheader) as the idempotency key when you call an external service. - Prefer “set to this value” operations over “add one”.
- Check for an existing result before you create one.