Skip to main content
Version: v5.6.1

3.2 Gates, retry, cancel

Included from Basic tier

After this you can: answer an approval gate, retry a failed run, and cancel a running one — and read what each leaves in the record.

Before you start — tick each one:

  • Lesson 3.1 — Your first change (opschain learn 3.1)

In the GUI: the run page lesson 3.1 followed shows the run's status, and the Reviews & approvals inbox lists every subject held for your approval.

Lesson 3.1 ran a change that went straight to success. Real changes park on a wait step, fail halfway, or need stopping — and each of those moments is a verb with an audit record. This lesson walks the four verbs an operator answers a run with: continue/approve/reject on a gate, cancel in flight, retry after a failure, and pause as the gentler hold. Every step below uses the pick action from lesson 2.3 — its wait step is what gives you a run to hold, cancel and retry.

1. Answer the gates​

A wait: step (lesson 2.3) in a server-side change parks on the server — the run holds at waiting until someone answers:

opschain runs create change acme/environments/dev --action pick
created change 01a13f20-…-example (pick on acme/dev) — pending

Find the waiting step's id in the run's step tree, then answer it:

opschain runs show <run-id> -o json | grep -B4 '"waiting"'
"id": "01a13f20-…-example",
"path": "pick/pick_window",
"name": "pick_window",
"kind": "wait",
"status": "waiting",
opschain runs continue <run-id> --step 01a13f20-…-example --message "window confirmed"
continued step 01a13f20-…-example of run <run-id> — now success

continue answers a plain wait step; approve and reject answer an approval-gated one, and only the required approvers may:

opschain runs approve <run-id> --step <step-id> --message "LGTM"
opschain runs reject <run-id> --step <step-id> --message "not tonight"
approved step <step-id> of run <run-id> — now running

The --message is recorded in the audit events. A step that is not waiting for that answer is refused by the server with a named error — you cannot approve the wrong thing by accident. Who counts as a required approver is the access model's territory (lesson 7.2); until then, the login from lesson 0.1 can answer every gate. Governed sign-off — named approvers, quorum, the approvals inbox — is an approval policy that holds the whole run before it starts: lesson 10.1 (opschain learn governance-approvals).

2. Cancel a run in flight​

Create a second pick change and let it park on its wait step; this time, instead of answering, cancel it:

opschain runs cancel <run-id> --reason "change window closed"
cancelled run <run-id>

The optional --reason (up to 1000 characters; the GUI's cancel dialog sends the same field) is recorded on the cancel audit event and appended to each cancelled step's audit trail as cancelled via API: <reason>. The run finalises cancelled, and an executing step is aborted on its runner within one lease-renewal round-trip, freeing that runner for the next run. An already-finished run is refused with the server's named error:

Error: the server answered failed_precondition: Cannot cancel because it is in the "cancelled" state

3. Retry a failed run​

A retry needs a run that did not succeed: the server retries a change in error, cancelled, aborted or rejected state and refuses a successful one by name (Change must be in error, cancelled, aborted or rejected state to be retried). The change you just cancelled is the subject:

opschain runs retry <run-id>
created change 01a13f31-…-example (pick on acme/dev) — queued

A retry is a new run duplicating the failed one — the original stays untouched as evidence (still cancelled in runs list), which is why the output is a fresh created line. Steps that succeeded are preserved and do not execute again; the failed subtree re-runs — here the duplicate parks on the wait step again, and continue finishes it. --follow works exactly as on create. If part of the tree is still known-broken, replace the skip mask for the retry:

opschain runs retry <run-id> --skip-step "deploy/optional_bit/**"

A retry normally re-runs at the original's pinned commit. For a project or environment git change you can instead re-resolve the branch or tag to its current head and pin the duplicate to the moved head:

opschain runs retry <run-id> --refresh-git-rev

A sha rev re-resolves to itself, and an asset change refuses the option with a named error (its commit comes from its template version, lesson 3.4).

4. Pause instead of killing​

To hold a run without killing it, pause it — the step that is running finishes, nothing new starts, gates still answer, and the hold survives a server restart:

opschain runs pause <run-id> --reason "change window closed"
paused run <run-id> — pause state pausing

pausing means a step is still finishing; it settles to paused when nothing is running. Release it when the window reopens:

opschain runs resume <run-id>
resumed run <run-id> — pause state none

The pause and resume are audited in the run's paused_by history. Pausing a paused or finished run, and resuming an unpaused one, are refused with the server's named errors.

Check yourself​

  • Park a change on a wait step, cancel it and retry it: what status does runs show report while it waits, which states may be retried, and what does runs retry print that proves the cancelled attempt's record is untouched?

What you learned​

  • A wait or approval step holds the run at waiting; continue, approve and reject answer it by step id, with the --message audited.
  • cancel --reason ends a run and aborts its executing step on the runner; a finished run refuses a second cancel by name.
  • A retry needs an error, cancelled, aborted or rejected run — a success is refused by name; it is a new run (created change …) that re-runs only the failed subtree, and --refresh-git-rev moves a git change to the branch's current head.
  • pause/resume hold a run between steps without killing anything.
  • Every one of these verbs leaves an audit event with its actor and message — the record lesson 5.1 reads.

Next: lesson 3.3 — Git remotes and the identity policy (opschain learn 3.3), or back to your track (opschain learn).