Skip to content

Workflow Cancellation Display Status Reliability improvements

Enhancement

What changed

We overhauled how CircleCI handles workflow cancellation to eliminate two long-standing issues: jobs that flip from canceled to success, and jobs that keep showing a spinner after they’ve actually finished.

Background

Previously, when a workflow was canceled, CircleCI would eagerly mark all jobs as canceled — before those jobs had actually stopped running. This caused two visible problems:

  • Status flipping: A job marked canceled may have already finished running. The actual confirmation would then arrive with the actual status and overwrite the result. Users would see jobs flip canceled → success.
  • Phantom spinners: Jobs were marked canceled and archived before receiving confirmation and an end timestamp. The UI interprets a job with a start time but no end time as still running, so completed jobs kept spinning indefinitely.

The fix

CircleCI no longer marks jobs canceled until they’ve actually stopped. Instead:

  1. It records a “canceling” inten
  2. It sends cancel signals only to jobs that are pending or running.
  3. It waits for each job to confirm it has stopped before recording the final status.

Downstream blocked jobs are left untouched and transition to skipped / not_run through the normal state engine, as expected.

Impact

  • Canceled jobs with a terminal end time: ~51% → 99%+
  • No more canceled → success status flips
  • No more phantom spinners for jobs that have already finished

What’s next

We’re migrating the single-job cancel path to the same defer-to-:job-ended model. This closes the remaining gap where individually canceled jobs can still report a start time but no end time.

Previous changes