먼저 답부터 말씀드리면: 최신 커밋이 생겼다는 이유만으로 이전 CI 실행을 모두 취소하면 안 됩니다. lint·단위 테스트·preview처럼 최신 결과가 이전 결과를 완전히 대체하는 읽기 전용 검증은 최신 실행 우선 정책을 검토할 수 있습니다. 반면 배포·migration·패키지 발행·외부 API 호출처럼 상태를 바꾸는 작업은 순차 실행, 승인, 복구 증거를 먼저 갖춰야 합니다.

AI 코딩 에이전트가 PR을 수정할 때마다 CI·검증·배포 workflow를 다시 시작한다면, 이전 실행은 언제 취소해도 될까요? 판단 기준은 ‘최신 커밋인가’가 아니라 ‘최신 결과가 이전 결과를 완전히 대체하는가’입니다. 이 글에서는 GitHub Actions의 동시 실행 제어를 바탕으로, 취소 가능·큐잉 필요·보류를 재현 가능하게 고르는 6칸 supersession 계약을 정리합니다.
핵심 요약
- GitHub Actions는 동시 실행 그룹을 제한할 수 있으며, 기본 동작에서는 그룹당 pending run 하나만 남고 추가 pending run이 이전 pending run을 취소할 수 있습니다.
- 순서대로 실행되어야 하는 작업은 취소 대신 queuing을 선택할 수 있습니다.
- 취소된 run은 성공이나 안전한 완료의 증거가 아닙니다. run ID·commit SHA·artifact·외부 행동 여부를 따로 확인해야 합니다.
- 공통 reusable workflow에서는 caller와 called workflow가 같은 concurrency group을 쓰는 조합이 의도치 않은 취소를 만들 수 있으므로, 복사 전에 한 PR 파일럿이 필요합니다.
GitHub Actions의 동시 실행 제어가 하는 일
GitHub Actions 공식 문서는 workflow나 job의 동시 실행을 제어해 충돌과 예상 밖의 리소스 사용을 줄일 수 있다고 설명합니다. 동시성을 제한하면 기본적으로 같은 그룹에 pending run 하나만 남고, 추가 pending run은 앞선 pending run을 취소합니다. 반대로 취소 없이 차례대로 실행해야 한다면 queuing을 선택할 수 있습니다. 이는 실행 순서를 다루는 기능 설명이지, 중단된 작업의 외부 효과를 되돌린다는 보장은 아닙니다.
예를 들어 PR의 lint와 단위 테스트는 같은 PR의 최신 커밋 결과가 이전 커밋 결과를 대체하는 경우가 많습니다. 그러나 production deploy는 이전 run이 이미 일부 인스턴스를 바꾸었을 수 있습니다. 두 작업 모두 “CI”라는 이름을 쓰더라도 취소 판단은 달라져야 합니다.
실행이 취소되었는지와 외부 상태가 바뀌었는지는 다른 질문입니다. 취소 표시는 작업이 끝났다는 영수증이 아닙니다.
AI 코딩 에이전트의 반복 실행에서 위험이 커지는 이유
에이전트는 수정·재시도·추가 검증을 빠르게 반복할 수 있습니다. 그만큼 같은 PR에 여러 run이 겹치고, 오래된 artifact가 새 결과처럼 보이거나, 공통 workflow가 호출자와 같은 group을 공유하는 일이 생길 수 있습니다. 속도를 얻으려면 어떤 실행이 대체 가능한지와 어떤 실행이 순서를 가져야 하는지를 workflow 이름이 아니라 업무 효과로 적어야 합니다.
실패 조건도 구체적으로 정해 두는 편이 좋습니다. 예를 들어 최신 테스트 run은 통과했지만, 취소된 이전 run이 만든 preview URL 또는 artifact가 검토 화면에 남아 있다면 팀은 무엇을 기준으로 판단할지 혼란스러워집니다. 배포나 외부 API 호출이 섞였다면 “취소됨”만으로는 중간 상태가 남지 않았는지 알 수 없습니다.
취소 정책을 문서로 바꾸는 6칸 supersession 계약
YAML을 먼저 복사하기보다, 아래 여섯 칸을 한 workflow 단위로 채워 보세요. 빈 칸이 있으면 빠른 취소보다 큐잉 또는 보류가 안전합니다.

- 대상
group이 PR·branch·환경·고객 작업 중 무엇을 대표하는지 적습니다. 서로 다른 환경을 같은 group에 묶으면 의도치 않게 서로를 막을 수 있습니다. - 대체 가능성
최신 run이 이전 결과를 완전히 대체하는지 확인합니다. 결과가 단순 검증인지, 누적 순서가 의미 있는지 구분하세요. - 부작용 경계
파일 업로드, 배포, migration, package publish, 외부 API write처럼 중단 뒤에도 남는 행동을 나열합니다. - 취소 증거
run ID, commit SHA, 취소 시점, artifact, deployment, 외부 action, 담당자를 한 기록으로 연결합니다. - 큐잉·복구
순서가 필요하면 queuing을 선택하고, 중간 취소 뒤 검사·정리·재개를 누가 수행할지 정합니다. - 제한 파일럿
한 PR의 읽기 전용 CI만 대상으로 빠른 재실행을 시험하고, 중단 기준을 통과한 뒤에만 범위를 넓힙니다.
작업별로 취소·큐잉·보류를 고르는 판단표
| 작업 유형 | 최신 결과가 이전 결과를 완전히 대체하나요? | 권장 정책과 확인 증거 |
|---|---|---|
| lint·단위 테스트 | 대체로 그렇습니다. 같은 PR·같은 검증 기준이라면 최신 commit의 결과가 중심입니다. | 제한적 취소 검토 최신 run의 SHA·결과·필수 check와 취소된 run의 상태를 함께 남깁니다. |
| preview 생성 | 검토 대상이 최신 commit 하나로 명확할 때만 그렇습니다. | 조건부 취소 남은 preview URL과 artifact가 최신 SHA를 가리키는지 확인합니다. |
| database migration | 아닙니다. 순서와 중간 상태가 의미를 가질 수 있습니다. | 큐잉 또는 보류 적용 여부, 현재 schema 상태, 점검·복구 담당자를 남깁니다. |
| package publish | 아닙니다. 이미 배포된 버전은 취소 뒤에도 남을 수 있습니다. | 큐잉·승인 발행된 버전, registry 상태, 재발행·폐기 절차를 확인합니다. |
| production deploy·외부 API write | 자동으로 판단할 수 없습니다. | 별도 group·승인·복구 배포 이력 또는 외부 action ID, 실제 상태, 중단·복구 책임자를 확인합니다. |
이 표는 모든 조직에 같은 설정을 권하는 규칙이 아닙니다. 운영 환경과 도구가 다르므로, 각 행의 확인 증거가 실제로 수집되는지 먼저 확인해야 합니다. FLOWIT 관점에서는 속도만이 아니라 비용·권한·신뢰성·운영 책임·결과 품질이 동시에 설명될 때만 자동 취소 범위를 넓힙니다.
reusable workflow에서 group 이름을 그대로 복사하면 안 되는 이유
GitHub 문서는 cancel-in-progress: true를 사용하면서 caller와 called workflow의 jobs.<job_id>.concurrency.group에 같은 값을 두지 말라고 안내합니다. called workflow의 github.workflow가 caller workflow 이름을 사용하기 때문에, 같은 값을 쓰면 called workflow가 실행될 때 이미 실행 중인 caller workflow가 취소될 수 있습니다.
따라서 공통 검증 workflow를 재사용한다면 group을 “보기 좋은 이름”으로만 정하지 마세요. 호출자·피호출자, PR과 환경, 읽기 전용과 상태 변경 작업을 구분하는 이름과 파일럿을 함께 설계해야 합니다. 이 주제는 reusable workflow의 권한 경계를 검토할 때도 같이 확인할 수 있습니다.
한 PR의 읽기 전용 CI로 시작하는 제한 파일럿

처음부터 전체 workflow에 적용하지 말고, 외부 상태를 바꾸지 않는 한 PR의 lint·단위 테스트로 시작하세요. 의도적으로 짧은 간격의 수정 또는 재실행을 만들고, 이전 run·최신 run·artifact가 각각 무엇을 의미하는지 확인합니다. 실제 production secret, 고객 데이터, 외부 write는 이 파일럿에 넣지 않습니다.
- group이 하나의 PR 또는 branch를 정확히 가리키는지 기록합니다.
- 이전 run의 상태를 성공으로 집계하지 않고, run ID와 commit SHA를 남깁니다.
- 최신 run의 필수 check와 artifact가 같은 SHA에 연결되는지 확인합니다.
- 오래된 preview, artifact, 알림이 남아 검토자를 혼동시키지 않는지 확인합니다.
- 외부 write 또는 결과 불명확 상태가 발견되면 자동 취소 범위를 넓히지 않고 보류합니다.
취소된 run이 외부 상태를 남겼는지 확인할 수 없거나, 최신 artifact를 특정 commit에 연결할 수 없거나, 책임자가 복구 절차를 설명할 수 없다면 파일럿을 멈추세요. 이때는 큐잉 또는 별도 group이 더 나은 선택입니다.
운영 기록을 결과 영수증과 연결하세요
CI 상태와 실제 업무 결과를 같은 것으로 보지 않는 습관이 중요합니다. 정기 작업의 실행 상태와 업무 결과를 분리해 기록하는 방법은 AI 에이전트 정기 작업의 결과 영수증 글에서 이어서 볼 수 있습니다. 외부 행동이 중복되거나 중단될 때는 action ID와 상태 확인 계약도 함께 참고해 보세요.
재시도가 필요할 때도 마찬가지입니다. 결과가 불명확한 외부 write를 같은 방식으로 덮어쓰지 말고, 도구 재시도와 escalation 기준처럼 멈춤과 확인의 경계를 먼저 남기는 편이 좋습니다.
자주 묻는 질문
cancel-in-progress를 켜면 이전 run은 항상 안전하게 사라지나요?
아닙니다. GitHub Actions의 취소 상태는 외부 시스템의 상태 복구를 보장하지 않습니다. 읽기 전용 검증인지, 외부 변화가 남는 작업인지부터 나누어야 합니다.
모든 CI를 하나의 concurrency group으로 묶어도 될까요?
권하지 않습니다. PR 검증, preview, migration, 배포처럼 대체 가능성과 순서 요구가 다른 작업은 서로 다른 경계를 가져야 합니다.
취소 대신 큐잉을 선택해야 하는 대표적인 경우는 무엇인가요?
migration, package publish, 배포처럼 순서와 중간 상태가 중요한 작업입니다. 앞선 작업의 실제 상태를 확인한 뒤 다음 작업을 실행할 수 있어야 합니다.
reusable workflow가 있으면 어떤 점을 먼저 시험해야 하나요?
caller와 called workflow의 group 값, cancel-in-progress 조합, 그리고 이미 실행 중인 caller가 예상치 않게 취소되지 않는지를 한 PR에서 확인하세요.
제한 파일럿을 통과하면 배포 workflow에도 바로 적용해도 되나요?
아닙니다. 읽기 전용 CI에서 얻은 결과를 상태 변경 작업에 일반화하면 안 됩니다. 배포는 별도 group, 승인, 실제 상태 확인과 복구 계획을 갖춘 뒤 별도로 검토해야 합니다.
마무리: 빠른 실행보다 설명 가능한 취소를 만드세요
최신 run만 남기는 정책은 잘 설계하면 대기 시간과 혼선을 줄일 수 있습니다. 하지만 좋은 정책은 이전 run을 숨기는 정책이 아니라, 어떤 결과가 무엇을 대체했고 무엇은 대체하지 못하는지 설명할 수 있는 정책입니다. 6칸 계약을 한 PR의 읽기 전용 CI에서 먼저 검증한 뒤, 증거와 복구 경계를 갖춘 작업에만 조심스럽게 확대해 보세요.
참고 자료
- GitHub Docs — Concurrency: workflow·job 동시 실행 제어, pending run 처리, queuing 선택의 범위를 설명합니다.
- GitHub Docs — Reusing workflow configurations: reusable workflow의 caller/called concurrency group 충돌 주의사항과 권한 경계를 설명합니다.
이 글이 마음에 드세요?
FLOWIT on YouTube
영상으로도 FLOWIT을 이어서 보세요
AI 자동화, Claude Code, n8n, 데이터 분석 흐름을 블로그와 영상으로 함께 정리하고 있습니다.
AI 데이터 에이전트, 데이터를 옮기지 않고 분석해도 될까? 연합 조회 전 6칸 지표 일치 카드
GitHub Actions 재사용 워크플로, YAML 중복만 보고 묶지 마세요
AI 코딩 에이전트 의존성 변경, 병합 전 6칸 판단표