Saga compensations
> **Work in progress.** Saga compensations are implemented in the native > engine. CI targets lower steps to native jobs; compensation on CI is a > follow-up.
Work in progress. Saga compensations are implemented in the native engine. CI targets lower steps to native jobs; compensation on CI is a follow-up. APIs may change.
When a run ends in failure, the engine automatically runs compensation
operations for succeeded steps that declared one, in reverse completion
order. A compensation undoes a step's side effects — rollback a deploy,
delete a created resource, send a cancellation notice.
Inspired by the Temporal saga pattern, but deliberately simpler: no compensation transactions, no forward recovery, no per-branch scoping — just ordered rollback of completed work.
Declaring a compensation
import { Project, Pipeline, ShellStep, Entry } from "@sverka/workflow";
const proj = new Project("myproj");
const p = new Pipeline(proj, "ci");
new ShellStep(p, "deploy", {
command: "kubectl apply -f deploy.yaml",
compensation: {
kind: "shell",
command: "kubectl rollout undo deployment/my-app",
},
});
new ShellStep(p, "notify", {
command: "curl -X POST $WEBHOOK_URL",
dependsOn: ["deploy"],
});
new Entry(p, "on-push", { trigger: { kind: "push" }, roots: ["notify"] });How it works
- The engine tracks the order steps succeed during a run.
- If the run ends in
failure(notcancelled), the engine walks the completion list backwards and executes each step's compensation. - Compensations run serially via the step's own runtime driver in the step's workspace.
- A failed compensation emits a
warndiagnostic but does not block subsequent compensations — best-effort rollback. - If
cancel()fires during the compensation phase, remaining compensations are skipped (the abort signal is checked before each compensation).
Events
| Event | When |
|---|---|
step-compensating | A compensation is about to run (carries command) |
step-compensated | A compensation finished (carries status: "succeeded" | "failed" and durationMs) |
Limitations (v1)
- Shell only. Compensation operations must be
kind: "shell". Other kinds raise a synthesis error. - No retries. A compensation runs once. If it needs retry, the command itself implements it.
- No cancellation compensation. Cancelled runs do not trigger compensations — cancellation is intentional.
- No branch scoping. v1 compensates ALL succeeded steps with a declared compensation, in reverse completion order.
- No CI equivalent yet. Compiled workflows lower steps to
target-native constructs;
if: failure()-style compensation lowering is a follow-up.