본문으로 건너뛰기
개발 머꼬
개발 노트GitHub Actions
hohyeon.dev27

같은 브랜치에 연속으로 push했더니 오래된 배포가 최신 배포를 덮어쓴 이유

  • #CI/CD
  • #Engineering Note
  • #GitHub Actions

문제 발생

짧은 시간 안에 커밋을 두 번 연달아 push했는데, 배포가 끝난 뒤 서버에 반영된 코드가 최신 커밋이 아니라 그 직전 커밋의 것이었습니다.

원인 분석

GitHub Actions는 기본적으로 같은 브랜치에 여러 번 push하면 각 push마다 독립적인 워크플로우 실행을 병렬로 시작합니다. 두 실행(A: 이전 커밋, B: 최신 커밋)이 동시에 진행될 때, 만약 A가 B보다 늦게 끝난다면(예: A가 실행되던 러너가 일시적으로 더 느렸거나, 큐잉 순서가 꼬였다면), A의 배포 단계가 B보다 나중에 실행되어 최신 코드를 이전 코드로 덮어쓰는 상황이 생길 수 있습니다.

이건 각 실행 자체는 정상적으로 성공했기 때문에 CI 로그만 봐서는 알아채기 어렵습니다 — 두 실행 다 초록색 체크가 뜨지만, 실행 순서가 꼬여 결과적으로 잘못된 버전이 배포된 것입니다.

해결 방안

concurrency 설정으로 같은 그룹의 이전 실행을 자동으로 취소하도록 만듭니다.

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

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps: [...]

group으로 지정한 값이 같은 워크플로우 실행끼리 하나의 그룹으로 묶이고, 같은 그룹 안에서 새 실행이 시작되면 cancel-in-progress: true 설정에 따라 진행 중이던 이전 실행이 자동으로 취소됩니다. 결과적으로 항상 가장 최근에 시작된 실행만 끝까지 진행되므로, 오래된 실행이 나중에 완료되며 최신 배포를 덮어쓰는 문제 자체가 사라집니다.

  1. group 값에 github.ref(브랜치/태그 참조)를 포함시키면 브랜치별로 독립된 그룹이 됩니다 — main에 대한 취소가 다른 브랜치의 실행에는 영향을 주지 않습니다.
  2. 테스트/빌드 job에는 취소를, 프로덕션 배포 job에는 신중하게 적용하는 것이 일반적입니다 — 빌드 중간에 취소되는 것은 자원 낭비를 줄이는 순수한 이득이지만, 실제로 서버에 반영 중인 배포 단계를 무작정 취소하면 어중간한 상태로 배포가 끊길 위험도 있으므로, 배포 job은 어디까지 진행됐을 때 취소해도 안전한지 별도로 검토합니다.
  3. PR마다 여러 번 push하는 것이 흔한 워크플로우에서는, pull_request 트리거에 이 설정을 적용하는 것만으로도 불필요하게 쌓이는 CI 실행/비용을 크게 줄일 수 있습니다.
  4. cancel-in-progress: false(또는 생략)로 두면 취소 없이 그냥 순서대로 큐잉만 시키는 것도 가능합니다 — 취소가 아니라 "최신 것이 이전 것을 기다리지 않고 뒤에 줄 서게"만 하고 싶은 경우에 씁니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.