GitHub Actions: cancel the Sume Format run when the job is canceled
A canceled GitHub job does not stop a Sume run. Add a step with if: cancelled() that posts to the run's cancel URL, within GitHub's 7.5 second signal window.

Canceling a GitHub Actions workflow stops your runner, not the Sume run it started. To stop the Sume side too, add a later step with if: cancelled() that posts to POST /v1/format-runs/{run_id}/cancel. GitHub re-evaluates step conditions on cancellation and keeps running steps whose condition is true, so the cleanup step runs.
The GitHub facts are from Workflow cancellation and the expressions reference, both read 2026-10-10. The Sume facts are from Runs and results.
What happens on cancel?
The page describes the sequence. Step if conditions are re-evaluated, and steps whose condition is true keep running. The running step receives SIGINT; after 7500 ms it gets SIGTERM, and after another 2500 ms it is killed. The server force-terminates the workflow after a 5 minute cancellation timeout. The expressions page says cancelled() is true when the workflow was canceled, always() runs even when canceled, and !cancelled() is the recommended alternative to always().
The timing is worth remembering: from the first signal to the kill of the running step is 7.5 plus 2.5, which is 10 seconds. A poll loop in bash should trap SIGINT or SIGTERM and exit quickly, so the cleanup step starts without waiting out the force-terminate timeout of 5 minutes.
| Moment | What GitHub does | What to do with Sume |
|---|---|---|
| Cancel requested | Re-evaluates step conditions; true ones keep running | A step with if: cancelled() is scheduled |
| Running step | SIGINT, then SIGTERM after 7500 ms, then kill after 2500 ms | Do not rely on the poll step to clean up |
| Cleanup step | Runs if its condition is true | Posts the Sume cancel |
| 5 minutes | The server force-terminates | Keep the cleanup step short |
What does the cancel call do?
Per the runs page, POST /v1/format-runs/{run_id}/cancel needs the formats:write scope, is idempotent, and returns cancel_effect of canceled or no_op. A cancel at any point is accepted, and you pay for the generation completed so far. If the run already ended, the result is no_op, which is harmless.
That makes it safe to call from a cleanup step even when you do not know the state. The call does not need the run to be in progress.
How do I wire it?
The submit step must save the run id where later steps can read it. Writing it to $GITHUB_ENV works for steps in the same job. The cleanup step reads the variable; if the submit never happened, the variable is empty and the step should do nothing.
Put the cleanup step last and give it a condition on cancellation only. Use cancelled() rather than always() so a normal failure does not cancel a run you may want to inspect.
Test it. Start a run in a scratch repository, cancel the workflow from the Actions page, then read the run by id. You should see a canceled status and a cancel_effect in the response of the cleanup step.
- name: Submit
run: |
ID=$(curl -sS -X POST https://api.sume.com/v1/formats/acme/promo/runs \
-H "Authorization: Bearer $SUME_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: gh-${{ github.run_id }}" \
-d '{"input":{"sku":"A-100"}}' | jq -r .data.id)
echo "SUME_RUN=$ID" >> "$GITHUB_ENV"
- name: Cancel the Sume run
if: cancelled()
run: |
[ -n "$SUME_RUN" ] && curl -sS -X POST "https://api.sume.com/v1/format-runs/$SUME_RUN/cancel" \
-H "Authorization: Bearer $SUME_API_KEY"What are the limits of this?
The step runs only if the runner still has a connection and the key is still available to the job. If the environment holds the key behind a reviewer gate, the secret was already given to the job at start, so the cleanup step has it. A runner that is lost does not run the step, so also set a budget on the request. The spend cap bounds the loss, and the run's own deadline force-finalizes it at 90 minutes.
This applies to Format runs. Plain jobs behave differently: a job cancel works only before generation starts, and later returns 409 job_generation_already_started.
Sources
Related posts
More in Integrations
- GitHub Actions matrix cap is 256 jobs: use Sume bulk runs instead
A GitHub Actions matrix can create 256 jobs, and a Sume bulk run takes 100 items. How to split a batch between them so concurrency and queue limits hold.
- GitHub environment reviewers: approve before a paid Sume run
Put the Sume key in a GitHub environment with required reviewers, so a workflow pauses for approval before it starts a paid run, then cap the run's spend.
- GitLab resource_group: one Sume bulk queue at a time
Use a GitLab resource_group so two pipelines never submit a Sume bulk run together, and pick the process mode that matches how stale a queued batch may be.
- Cloud Scheduler retryCount max 5: key the Sume submit by slot
Cloud Scheduler retries a failed target up to 5 times, and a retried call looks like a new request. Key the Sume submit by the schedule slot, not the retry.
Written by Sume