Summary#
A run in flight goes on executing the version it started under — deliberately, and permanently. That is the guarantee that makes deploying safe while work is in progress.
It is also a trap the first time you ship something broken. You notice, you deploy the fix, and the fix only applies to
new runs: every run already started keeps executing the broken code to completion. cancel-runs is how you stop them.
Signature#
$ osy cancel-runs --version <version> # local
$ osyrin app cancel-runs <version> # a deployed appDescription#
What it does#
Every workflow run still in flight against the named version is stopped: marked cancelled, recorded in the run's audit timeline as such, and any parked continuation discarded so nothing can wake it again. Runs on other versions are untouched.
Find the version with Deploying while workflows are running — the In flight column is what you are about to cancel:
$ osy versions
$ osy cancel-runs --version 1.1.0It tells you how many runs you are about to stop and asks before doing it. --yes skips the prompt.
It stops whole sagas, not single runs#
A saga is a tree: a parent waiting on a child, which may itself be waiting on another. Cancelling one run of that tree cancels all of it, whichever run you name.
That is not overreach, it is the only coherent option. Cancelling just the child would leave the parent waiting forever on something that can never finish — one stuck run traded for another. Cancelling just the parent would leave children doing work whose result nothing will ever read.
It does not run your compensation logic#
This is the important one, and it is deliberate.
When a saga fails normally, its catch runs and compensates — undoing what it did. Cancelling does not do that. The
reason you are reaching for cancel-runs is usually that the deployed code is wrong, and your compensation logic is
that same deployed code. Running it would execute the very thing you are trying to escape, and on a saga that is already
in a state you did not intend.
So: side effects those runs already performed remain performed. Money moved stays moved, emails sent stay sent. The audit says the run was cancelled, not that it was compensated, so the record does not claim an unwind that never happened. Undoing that work is yours to do deliberately — with full knowledge of what actually ran.
Cancelling is a blunt instrument on purpose. It is the tool for "stop, this is wrong", not for "unwind this cleanly".
It also lets the version be cleaned up#
Runs in flight are exactly what stops an old version being reclaimed. Once you have cancelled them, nothing holds that
version open and the next deploy reclaims it — so the broken version stops appearing in versions too.
Who can run it#
The same permission as deploying to the app. Whoever can ship the bad version can stop it.
Examples#
The whole sequence, from noticing to clean:
# 1. What is running, and against which version?
osy versions
# → 1.2.0 app_v3 14 in flight oldest 09:12 (2h ago) held by runs in flight
# 1.3.0 app_v4 0 — current
# 2. Deploy the fix. New runs are fine from here; the 14 are not.
osy compile --new-version
# 3. Stop the runs still executing the broken version.
osy cancel-runs --version 1.2.0
# → About to cancel 14 run(s) in flight against version 1.2.0 (app_v3).
# No compensation runs. Side effects those runs already performed will remain.
# Continue? [y/n]
# 4. Nothing holds app_v3 now, so the next deploy reclaims it.
osy versionsSee also#
- Deploying while workflows are running — why a run keeps its own version in the first place, and how to see what is in flight
- Workflow.Run (start a workflow) — the parent/child await that makes a saga a tree