A busy branch receives several pushes a minute and the CI queue keeps growing. What does grouping runs under a concurrency key and cancelling superseded runs buy you, and where is that dangerous?
answer
- one active run per key
- the older one is already stale
- never cancel a deploy mid-flight
- a key with the commit in it collides with nothing
- you lose which commit broke it
basics
~20 sGrouping runs by a key such as the branch or proposal, and cancelling the older in-flight run when a newer one arrives, keeps at most one active run per key. It cuts queue depth and spend, since only the newest commit's result is usually wanted — but cancelling deploys is unsafe.
solid answer
~60 sA concurrency key groups runs that are interchangeable — typically one key per branch or per proposal — and the platform then enforces at most one active run per key, either by queueing the newcomer or by cancelling the run already in flight. Superseding is the aggressive form: when push five arrives, the run for push four is killed. On a busy branch that removes most of the queue and most of the bill, and it is usually correct, because nobody was going to read the result for a commit that is already three commits stale. It is dangerous in three places. Deploy and release jobs must never be cancelled mid-flight: you can be left with a partial rollout, a half-published artifact set, or a lock nobody released — for those, serialise instead, letting the newer run wait. You also lose per-commit signal, so you can no longer tell which of the superseded commits broke the build. And a key that is too coarse serialises unrelated work while a key that is too fine supersedes nothing.
go deeper
Know that CI can be told to keep only one run per branch and cancel the older one, and that this exists to stop stale runs from clogging the queue.
Explain how the key determines what counts as interchangeable, the difference between queueing and cancelling, and why a key containing the commit never collides.
Show the operational judgment: which pipelines may be superseded and which must serialise, what a cancelled deploy can leave behind, and how a cancelled required check blocks a merge.
Own the policy across teams — where the throughput/bisectability trade sits for trunk versus proposal pipelines, and how you keep cancellation from leaking cloud resources and locks at scale.
## The mechanism A concurrency key is a string computed per run. Runs sharing the key are considered interchangeable, and the platform enforces a limit — usually one — on how many may be active for that key at a time. When a new run collides with an active one, there are three possible policies: - **Queue**: the newcomer waits for the incumbent to finish. Nothing is lost; latency grows. - **Cancel-in-progress (supersede)**: the incumbent is killed and the newcomer starts immediately. - **Reject/skip the newcomer**: rarer, and usually wrong for CI because it means the newest commit is untested. ## Designing the key The key must contain enough to separate work that is *not* interchangeable, and no more: ``` key = pipeline identity + branch or proposal id [+ target environment for deploys] ``` - **Too coarse** (just the repository name): pushes to unrelated branches serialise behind each other, and the pipeline behaves as though you had one runner. - **Too fine** (including the commit SHA): every run has a unique key, so nothing ever collides and the mechanism does nothing at all. This is the most common misconfiguration, because it looks configured. - **Deploys** should key on the target environment, not the branch, since two different branches deploying to the same environment genuinely conflict. ## What superseding actually saves On a branch receiving six pushes in ten minutes with a twelve-minute pipeline, superseding turns six overlapping runs into roughly one-and-a-bit runs of compute, and — more valuable than the money — it stops the queue from filling with results nobody will read. Feedback latency for the newest commit drops, because it no longer waits behind stale work for a free runner. ## Where it hurts **1. Deploys and releases.** Cancellation delivers a signal at an arbitrary point in a job. A rollout halfway through, an artifact uploaded but not tagged, a database migration part-applied, an infrastructure lock acquired and never released — all are reachable states. Deploy pipelines should queue rather than supersede, and where the queued work is obsolete on arrival the right pattern is *serialise, then let the newest one run last*. **2. Cleanup does not always run.** Cancellation is not a normal failure path. Steps written to run "always" often do run, but grace periods are short and a killed job can leave behind cloud resources, test databases, ephemeral environments or self-hosted runner state. Anything with an external side effect needs a reaper that is not part of the cancelled run. **3. Lost per-commit signal.** If commits A, B and C were superseded and D fails, you know only that something in A–D broke it. You have traded bisectability for throughput. On a shared trunk that is often the wrong trade, which is why many teams supersede aggressively on proposal branches and never on the default branch. **4. Merge gates and cancelled statuses.** A cancelled run reports as cancelled or failed, not as passed. If a required check was cancelled by superseding, the proposal can sit unmergeable until something re-runs it — a real source of "why is this PR stuck" tickets. Make sure the run that survives is the one whose status the gate reads. **5. Long-lived side effects mid-run.** A run that has already pushed an image or written a cache entry does not un-push it when cancelled. Partial artifacts from superseded runs are a known cause of confusing cache and registry state. ## A workable policy - Proposal branches: supersede freely; the only reader is the author and they care about the tip. - Default branch, build and test: usually queue rather than supersede, so every trunk commit keeps its own verdict and bisecting stays possible. - Deploy to an environment: key on the environment, queue with a limit of one, never cancel. - Anything holding an external lock or performing a migration: mark it non-cancellable and make the wait explicit. ## Diagnosing it If the queue is deep, first establish whether it is *concurrency* (too many runnable jobs, not enough runners) or *interchangeability* (many stale runs for the same branch). Superseding only fixes the second. If the pipeline is genuinely slow rather than duplicated, cancelling runs hides the symptom and the next busy day brings it back.
- Someone puts the commit SHA into the concurrency key and reports that nothing is ever cancelled. Why?Because every run then has a unique key, so no two runs ever collide and the limit is never reached. The key must contain only what makes runs interchangeable — the pipeline identity plus the branch or proposal — so that successive pushes to the same branch land in the same group. Including the SHA looks configured while disabling the feature entirely.
- How do you get the throughput benefit on a deploy pipeline without cancelling a deploy in flight?Serialise instead of superseding: key on the target environment with a limit of one, let the running deploy finish, and have pending runs wait. If several queue up, keep only the newest waiter and drop the intermediates — that gives you the same "only the latest matters" saving without ever interrupting a deploy that is mutating a real environment.
- What is the cost of superseding runs on the default branch specifically?You lose the per-commit verdict. When a later run fails you cannot tell which of the skipped commits introduced it, so bisecting means re-running history by hand. On a trunk that gates releases that is usually a bad trade, so most teams supersede on proposal branches and queue on the default branch, accepting a slower trunk pipeline for a clean per-commit record.
saying these in an interview costs you the question
- Applies cancel-in-progress uniformly, including to deploy jobs
- Puts the commit SHA in the key so nothing ever collides
- Assumes cleanup steps always complete on a cancelled run
- Thinks superseding fixes a queue caused by too few runners
- Forgets a cancelled required check leaves a proposal unmergeable