Course outline

GitHub Actions / Identity, coordination, and governance / Lesson 15

Concurrency groups, cancellation, and release freshness

Coordinate related work without assuming cancellation undoes an external operation.

About 4 min readContent reviewed
On this page

Lesson goals

  • Choose a concurrency key that represents the resource being coordinated.
  • Separate pending selection, running cancellation, and target-side freshness.

A group coordinates a particular namespace

Actions concurrency can restrict jobs or runs sharing a group in the repository. A useful group expresses the resource being coordinated: one proposal’s test feedback or one environment’s adoption path. Include enough context to avoid unrelated workflows canceling each other accidentally. Conversely, adding a unique run identifier defeats coordination because every run belongs to a different group. Parcel’s validation and release paths need different policies. Replacing outdated test work can be reasonable, while interrupting a state-changing operation requires careful target-side semantics.

Read the queue behavior for the selected platform

The reviewed GitHub.com documentation describes a default single pending slot: a new pending member replaces an existing pending member in the same group. It also documents an optional larger queue mode with its own limit and restrictions. These capabilities must be checked for the actual service or Enterprise Server version. Queue waiting order is not source revision order, because jobs reach the group after different preparation times. A concurrency group therefore does not prove that every commit will execute or that the newest source will be adopted last.

Cancel obsolete validation deliberately

The following workflow-level fragment groups validation by workflow name and ref, then cancels an in-progress member when newer work arrives. It is a non-runnable illustration for replaceable validation, not a release prescription. A pull-request ref and a branch ref have event-specific forms, so review which events should share a group. Group names are case-insensitive under documented behavior. When a shared reusable workflow participates, review its group expression too; an accidental collision can cancel the caller or another legitimate job.

yaml Replace obsolete validation work
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

This fragment contains no event or jobs and is never installed. Canceling validation does not prove that an external operation was canceled, and this setting should not be copied to adoption work without a reviewed state contract.

Recheck eligibility after waiting

Candidate r5 can finish preparation before a slower r4 candidate even if r4 started first. Serial adoption can still regress the target if r4 proceeds afterward. Recheck eligibility against an authoritative generation or release policy after obtaining coordination. Do not sort human labels as strings to infer chronology. The complete local model below rejects a smaller declared generation and deduplicates the same request. It deliberately omits transactions, concurrent workers, crashes, and distributed fencing, so it is not a production coordination implementation.

python Model sequential freshness and request identity
observed_generation = 5
completed = set()
def accept(request, generation):
    global observed_generation
    if request in completed:
        return "duplicate"
    if generation < observed_generation:
        return "stale"
    observed_generation = generation
    completed.add(request)
    return "accepted"
print(accept("lab-a", 4))
print(accept("lab-b", 6))
print(accept("lab-b", 6))
Expected output
stale
accepted
duplicate

The generation numbers are synthetic policy inputs. This program performs no job scheduling, lock acquisition, API call, or deployment.

Client cancellation can leave work behind

Canceling an Actions job stops or requests interruption of runner work according to platform behavior; it does not universally reverse an operation already accepted by an external target. Preserve request identity and inspect authoritative completion state before retrying. Separate submission, convergence, user verification, and reporting so one report failure does not repeat an adoption. Cleanup also needs ownership: a canceled job must not remove shared state now belonging to a newer request. Document the recovery path for unknown outcomes before enabling cancellation around side effects.

Common errors and fixes

Every group includes github.run_id.

Why it happens
A unique key prevents related runs from sharing coordination.
How to fix it
Choose a key representing the intended proposal or target resource.
Prevent it next time
Review examples of intended sharing and intended separation.

A lock is assumed to prevent an older release adopting later.

Why it happens
Mutual exclusion was confused with source freshness.
How to fix it
Recheck eligibility after waiting using authoritative release state.
Prevent it next time
Keep ordering and supersession policy explicit.

A canceled job is immediately retried as a new external request.

Why it happens
Client cancellation was treated as proof that no target effect occurred.
How to fix it
Observe the original operation and retain stable request identity.
Prevent it next time
Define cancellation, retry, and cleanup boundaries before release.

Check your understanding

1. Should independent staging and production adoptions always share one global group?

Show worked solution

Not necessarily. Use a target-specific boundary when the resources and policies are independent, while coordinating any truly shared state separately. A global group can create unnecessary waiting; an overly specific group can permit unsafe overlap.

2. Can the default pending replacement policy guarantee every migration executes?

Show worked solution

No. A replaced pending member may never run, and preparation timing differs from source order. A migration chain requiring every transition needs a reviewed ordering and state model rather than an assumption that concurrency queues are a durable migration ledger.

Key takeaways

  • Coordinate the actual resource and review queue semantics.
  • Cancellation, freshness, and idempotency are separate contracts.

Official references