워크플로와 잡의 동시성(Concurrency) 제어하기

워크플로와 잡의 동시성(Concurrency) 제어하기

어떤 워크플로와 잡이 동시에 실행될 수 있는지 관리할 수 있어요. 특히 배포처럼 순서가 중요한 작업에서 이중 실행을 막을 때 유용해요.

출처: 문서

본문

어떤 워크플로와 잡이 동시에 실행될 수 있는지 관리합니다.

다양한 시나리오에서 동시성 사용하기

jobs.<job_id>.concurrency를 사용해서 같은 동시성 그룹(concurrency group)을 사용하는 잡이나 워크플로가 한 번에 하나만 실행되도록 보장할 수 있습니다. 동시성 그룹은 아무 문자열이나 표현식이 될 수 있습니다. 허용되는 표현식 컨텍스트는 github, inputs, vars, needs, strategy, matrix입니다. 표현식에 대한 자세한 내용은 Evaluate expressions in workflows and actions을 참고하세요.

워크플로 레벨에서도 concurrency를 지정할 수 있습니다. 자세한 내용은 concurrency를 참고하세요.

즉, 동시성 그룹 안에는 언제나 최대 하나의 실행 중인 잡이나 워크플로만 존재할 수 있습니다. 동시 실행 잡이나 워크플로가 대기열에 들어갈 때, 저장소에서 같은 동시성 그룹을 사용하는 다른 잡이나 워크플로가 진행 중이라면 대기열에 들어온 잡이나 워크플로는 pending 상태가 됩니다. 기본적으로 같은 동시성 그룹의 기존 pending 잡이나 워크플로는 취소되고, 새로 대기열에 들어온 잡이나 워크플로가 그 자리를 차지합니다.

같은 동시성 그룹에서 현재 실행 중인 잡이나 워크플로까지 취소하려면 cancel-in-progress: true를 지정합니다. 같은 동시성 그룹에서 현재 실행 중인 잡이나 워크플로를 조건부로 취소하려면 허용되는 표현식 컨텍스트 중 하나로 cancel-in-progress를 표현식으로 지정할 수 있습니다.

같은 동시성 그룹에서 여러 pending 잡이나 워크플로 실행이 대기하도록 허용하려면 선택적 queue 속성을 사용합니다. queue 속성은 다음 값을 허용합니다:

  • single(기본값): 동시성 그룹에서 최대 하나의 잡이나 워크플로 실행만 pending 상태일 수 있습니다. 새 잡이나 워크플로 실행이 대기열에 들어가면 그룹의 기존 pending 잡이나 워크플로 실행이 취소되고 대체됩니다.
  • max: 동시성 그룹에서 최대 100개의 잡이나 워크플로 실행이 pending 상태일 수 있습니다. 대기열이 가득 차면 추가 잡이나 워크플로 실행은 취소됩니다.

queue: maxcancel-in-progress: true의 조합은 허용되지 않으며 워크플로 검증 오류가 발생합니다.

[!NOTE]

  • 동시성 그룹 이름은 대소문자를 구분하지 않습니다. 예를 들어 prodProd는 같은 동시성 그룹으로 취급됩니다.
  • 같은 동시성 그룹의 잡이나 워크플로 실행은 각 실행이 동시성 그룹에서 대기를 시작한 시간 순서(FIFO)대로 처리되며, 워크플로가 디스패치된 시간 기준이 아닙니다. 실제 잡이나 실행의 시작 시간은 다를 수 있으므로 순서는 보장되지 않습니다.

예시: 동시성과 기본 동작 사용하기

GitHub Actions의 기본 동작은 여러 잡이나 워크플로 실행이 동시에 실행되도록 허용하는 것입니다. concurrency 키워드를 사용하면 워크플로 실행의 동시성을 제어할 수 있습니다.

예를 들어, 특정 브랜치에 대한 전체 워크플로 실행의 동시성을 제한하려면 트리거 조건이 정의된 직후에 concurrency 키워드를 사용할 수 있습니다:

on:
  push:
    branches:
      - main

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

잡 레벨에서 concurrency 키워드를 사용해서 워크플로 내 잡의 동시성을 제한할 수도 있습니다:

on:
  push:
    branches:
      - main

jobs:
  job-1:
    runs-on: ubuntu-latest
    concurrency:
      group: example-group
      cancel-in-progress: true

예시: 동시성 그룹

동시성 그룹은 같은 동시성 키를 공유하는 워크플로 실행이나 잡의 실행을 관리하고 제한하는 방법을 제공합니다.

concurrency 키는 워크플로나 잡을 동시성 그룹으로 묶는 데 사용됩니다. concurrency 키를 정의하면 GitHub Actions가 해당 키를 가진 워크플로나 잡만 한 번에 하나씩 실행되도록 보장합니다. 새 워크플로 실행이나 잡이 같은 concurrency 키로 시작되면 GitHub Actions는 해당 키로 이미 실행 중인 워크플로나 잡을 취소합니다. concurrency 키는 하드코딩된 문자열이거나 컨텍스트 변수를 포함한 동적 표현식일 수 있습니다.

워크플로나 잡이 동시성 그룹의 일부가 되도록 워크플로에 동시성 조건을 정의할 수 있습니다.

즉, 워크플로 실행이나 잡이 시작되면 GitHub는 같은 동시성 그룹에서 이미 진행 중인 워크플로 실행이나 잡을 취소합니다. 이는 특정 워크플로나 잡 집합의 병렬 실행을 막고 싶은 시나리오(예: 스테이징 환경에 배포할 때)에서 유용하며, 충돌을 일으키거나 필요한 것보다 더 많은 리소스를 소모하는 작업을 방지할 수 있습니다.

이 예시에서 job-1staging_environment라는 동시성 그룹의 일부입니다. 즉, job-1의 새 실행이 트리거되면 staging_environment 동시성 그룹에서 이미 진행 중인 같은 잡의 실행이 모두 취소됩니다.

jobs:
  job-1:
    runs-on: ubuntu-latest
    concurrency:
      group: staging_environment
      cancel-in-progress: true

또는 concurrency: ci-${{ github.ref }} 같은 동적 표현식을 사용하면 워크플로나 잡이 ci- 뒤에 워크플로를 트리거한 브랜치나 태그의 참조가 붙은 동시성 그룹의 일부가 됩니다. 이 예시에서 이전 실행이 여전히 진행 중인 동안 main 브랜치에 새 커밋이 푸시되면 이전 실행이 취소되고 새 실행이 시작됩니다:

on:
  push:
    branches:
      - main

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

예시: 여러 pending 실행 대기열에 쌓기

기본적으로 동시성 그룹에는 한 번에 하나의 잡이나 워크플로 실행만 pending 상태일 수 있습니다. 취소 대신 여러 실행이 대기하도록 하려면 queue: max를 설정하세요. queue: max를 사용하면 최대 100개의 잡이나 워크플로 실행이 동시성 그룹에서 대기할 수 있고, 대기열이 가득 차면 추가 실행은 취소됩니다.

예를 들어, 다음 워크플로는 production 환경에 대한 배포를 대기열에 넣고, 각 실행이 동시성 그룹에서 대기를 시작한 순서대로 하나씩 처리합니다:

on:
  push:
    branches:
      - main

concurrency:
  group: production-deploy
  queue: max

queue: maxcancel-in-progress: true와 결합할 수 없습니다. 두 옵션은 진행 중인 실행을 처리하는 방식이 서로 상충되기 때문입니다.

예시: 동시성을 사용해서 진행 중인 잡이나 실행 취소하기

GitHub Actions에서 진행 중인 잡이나 실행을 취소하려면 cancel-in-progress 옵션을 true로 설정한 concurrency 키를 사용할 수 있습니다:

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

이 예시에서는 특정 동시성 그룹을 정의하지 않았으므로 GitHub Actions가 잡이나 워크플로의 모든 진행 중인 실행을 취소한다는 점에 유의하세요.

예시: 폴백(fallback) 값 사용하기

특정 이벤트에서만 정의되는 속성으로 그룹 이름을 만들면 폴백 값을 사용할 수 있습니다. 예를 들어 github.head_refpull_request 이벤트에서만 정의됩니다. 워크플로가 pull_request 이벤트 외에도 다른 이벤트에 응답한다면 구문 오류를 피하기 위해 폴백을 제공해야 합니다. 다음 동시성 그룹은 pull_request 이벤트에서만 진행 중인 잡이나 실행을 취소합니다. github.head_ref가 정의되지 않으면 동시성 그룹은 실행에 대해 고유하고 항상 정의되는 것이 보장된 실행 ID(run ID)로 폴백합니다.

concurrency:
  group: ${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

예시: 현재 워크플로의 진행 중인 잡이나 실행만 취소하기

같은 저장소에 여러 워크플로가 있다면, 다른 워크플로의 진행 중인 잡이나 실행을 취소하지 않도록 동시성 그룹 이름이 워크플로 간에 고유해야 합니다. 그렇지 않으면 워크플로와 무관하게 이전에 진행 중이거나 pending인 잡이 모두 취소됩니다.

같은 워크플로의 진행 중인 실행만 취소하려면 github.workflow 속성으로 동시성 그룹을 만들 수 있습니다:

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

예시: 특정 브랜치에서만 진행 중인 잡 취소하기

특정 브랜치에서는 진행 중인 잡을 취소하고 다른 브랜치에서는 취소하지 않으려면 cancel-in-progress에 조건부 표현식을 사용할 수 있습니다. 예를 들어 개발 브랜치에서는 진행 중인 잡을 취소하지만 릴리스 브랜치에서는 취소하지 않으려면 이렇게 할 수 있습니다.

릴리스 브랜치에서 실행되지 않을 때만 같은 워크플로의 진행 중인 실행을 취소하려면 cancel-in-progress를 다음과 비슷한 표현식으로 설정할 수 있습니다:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ !contains(github.ref, 'release/')}}

이 예시에서 release/1.2.3 브랜치로 여러 번 푸시해도 진행 중인 실행은 취소되지 않습니다. main 같은 다른 브랜치로 푸시하면 진행 중인 실행이 취소됩니다.

조직이나 엔터프라이즈의 현재 잡 모니터링하기

동시성이나 대기열 관련 제약이 있는지 확인하려면 조직이나 엔터프라이즈의 GitHub 호스팅 러너에서 현재 처리 중인 잡 수를 확인할 수 있습니다. 자세한 내용은 Viewing your current jobs를 참고하세요.

더 알아보기 (Learn more)