Guía9 min

Concurrency en GitHub Actions: un run por rama, cancel-in-progress con criterio

Resumen

El bloque concurrency agrupa runs. cancel-in-progress true mata el job anterior de la misma rama. Útil en PRs; peligroso en deploy a main. Un agente no copia cancel-in-progress: true en workflows de producción. Docs GitHub control concurrency.

GitHub
Dos runs del mismo workflow: el viejo se cancela, el nuevo sigue

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

Cada push a un PR dispara CI. Sin concurrency, se acumulan 8 jobs de la misma rama y se come minutos. El bloque:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

GitHub cancela el run anterior del mismo grupo cuando entra uno nuevo. En un PR de un agente que pushea 6 veces, es lo correcto. En workflow_dispatch de un deploy a prod, no: el deploy a medias queda a medias.

No sustituye gh pr. El curso instalar un agente no cubre colas de CI.

Grupos

El group es un string. Si dos workflows usan el mismo group, se pisan entre sí. Incluye github.workflow para no mezclar test y deploy.

Contextogroupcancel-in-progress
PR / push a featureci-${{ github.ref }}true
main deploydeploy-prodfalse (espera)
Nightlynightlyfalse

cancel-in-progress: false (default): el nuevo espera. Útil si no quieres matar un migrate.

PR cancela el run viejo

Qué no hace el agente

  • Copiar cancel-in-progress: true a todos los YAML.
  • Un group global ci para todo el repo (un PR cancela el deploy de otro).
  • concurrency a nivel job si el workflow ya lo tiene (doble, confuso).
  • Cancelar a mano con gh run cancel de jobs ajenos.

Receta AGENTS.md

PR CI: concurrency group per workflow+ref, cancel-in-progress true.
Deploy/prod: cancel-in-progress false.
Never share one group across unrelated workflows.

Deploy espera, no cancela

FAQ

¿Solo PRs? github.ref en refs/pull/1/merge vs refs/heads/main. Un group con ref separa prod.

¿Matrix? Concurrency del workflow aplica al run entero, no a cada shard por separado.

¿Reusable? El caller define concurrency; el callee no cancela al caller mágicamente.

¿Minutos? Cancelar ahorra. Un deploy a medias puede dejar schema a medias: más caro.

Un agente que pushea “wip” cada 30 s con cancel-in-progress nunca deja terminar el test largo. Agrupa commits o usa workflow_run. CI no es un save automático.

Verificado 2026-09-03 contra GitHub Docs — Control concurrency of workflows and jobs.