Concurrency: отмена лишних прогонов

Не гоняем зря старые сборки и не допускаем двух деплоев одновременно.

Concurrency — механизм, ограничивающий число одновременных прогонов в одной группе и умеющий отменять устаревшие.

Проблема гонок и лишней работы

Два сценария, где это критично:

  • Разработчик пушит три коммита подряд в ветку PR — стартуют три прогона CI, хотя актуален только последний. Два первых жгут минуты впустую.
  • Два деплоя на прод запустились одновременно — гонка, можно получить «полузадеплоенное» состояние.

Отмена устаревших прогонов CI

Для CI ветки хотим: при новом пуше отменить предыдущий незавершённый прогон этой же ветки.

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

Разбор:

  • group — ключ группы; одинаковый ключ = «одна очередь». Здесь группируем по ветке (github.ref).
  • cancel-in-progress: true — новый прогон отменяет ещё бегущий из той же группы.

Итог: на каждую ветку в любой момент живёт максимум один актуальный прогон.

Защита деплоя без отмены

Для деплоя поведение другое: отменять начатый деплой посреди процесса опасно. Здесь нужна очередь, а не отмена:

concurrency:
  group: deploy-production
  cancel-in-progress: false

Фиксированное имя группы (deploy-production) гарантирует, что одновременно идёт только один деплой; cancel-in-progress: false заставляет новые запуски ждать завершения текущего, а не прерывать его.

Уровень workflow и job

concurrency можно задать на уровне всего workflow (вверху файла) или отдельного job. Часто комбинируют: отмена для CI-job и очередь для deploy-job в одном файле.

Итог

  • concurrency.group объединяет прогоны в одну «очередь» по ключу (часто по ветке).
  • cancel-in-progress: true — для CI: отменяет устаревшие прогоны и экономит минуты.
  • cancel-in-progress: false + фиксированная группа — для деплоя: один за раз, без прерывания.
Проверьте себя
1. Что делает cancel-in-progress: true в блоке concurrency?
AЗапускает все прогоны параллельно
BОтменяет ещё выполняющийся прогон из той же группы при старте нового
CУдаляет логи старых прогонов
DБлокирует pull request
2. Почему для деплоя на прод обычно ставят cancel-in-progress: false?
AЧтобы деплой был быстрее
BЧтобы не прерывать уже идущий деплой и не получить «полузадеплоенное» состояние, выстроив запуски в очередь
CЧтобы отключить тесты
DЧтобы отменять все прогоны сразу
3. Зачем в группе CI обычно используют github.ref как часть group?
AЧтобы шифровать ветку
BЧтобы группировать прогоны по ветке: отмена касается только прогонов той же ветки
CЧтобы ускорить checkout
DЭто обязательное фиксированное значение
Поддержать проект