GitHub Actions 스케줄 자동화는 cron에 적은 시각에 반드시 시작되는 외부 스케줄러가 아닙니다. 공식 문서 기준으로 최소 실행 간격은 5분이지만, 고부하 때는 지연될 수 있고 매시 정각에는 대기 작업이 유실될 수도 있습니다. 따라서 정시성보다 “중복 실행 방지, 제한 시간, 실패 확인, 산출물 보존”을 먼저 설계해야 합니다.
이 글은 워크플로를 실제 저장소에서 실행하거나 지연 시간·비용 절감률을 측정한 사용기가 아닙니다. 2026년 9월 13일 GitHub 공식 문서에서 확인한 제한과 동작 범위를 제품 사양으로 적고, 설정 예시는 그 값을 운영 판단으로 옮긴 참고안으로 구분합니다.
광고나 제휴 여부와 무관하게 아래 공개 자료를 참고했습니다.
이 글에서 대조한 GitHub 공식 자료
GitHub 공식 문서 5건에서 schedule 이벤트의 실행 조건, 워크플로·job 한도, 플랜별 동시 실행 수와 무료 제공량, 아티팩트·로그 보존 기간을 각각 대조했습니다. 아래 표의 수치는 해당 원문 항목명을 함께 적었으며, 문서가 보장하지 않는 지연 상한이나 성공률은 별도 경계표에 남겼습니다.
- GitHub Docs: Events that trigger workflows — schedule — 지연·유실 가능성, 기본 브랜치, 60일 비활성화 조건.
- GitHub Docs: Workflow syntax — on.schedule — POSIX cron, UTC·IANA 시간대, 최소 5분, job 제한 시간.
- GitHub Docs: Actions limits — workflow run, job, matrix, 재실행, 파일 크기, 동시 job 한도.
- GitHub Docs: GitHub Actions billing — GitHub Free 2,000분·500MB·캐시 10GB와 저장량 계산 방식.
- GitHub Docs: Configuring the retention period for artifacts and logs — 기본 90일, 공개·비공개 저장소 조정 범위.
공식 문서의 확인값과 원문 항목명
| 구분 | 확인한 값·조건 | 공식 원문 항목명 | ⭐ 적용상 주의 |
|---|---|---|---|
| schedule 최소 주기 | 최단 5분마다 1회 |
on.schedule — “The shortest interval” |
5분 안에 시작하거나 매 5분마다 빠짐없이 완료된다는 뜻이 아님 |
| cron 형식 | 공백으로 구분한 5개 필드의 POSIX cron |
on.schedule — “Cron syntax has five fields” |
@daily·@reboot 같은 비표준 축약을 지원한다는 뜻이 아님 |
| 기본 시간대 | 기본 UTC; IANA 시간대 지정 가능 |
on.schedule — “By default … UTC” / timezone |
실행 머신의 로컬 시간대를 자동 추론하거나, DST 전환 시 존재하지 않는 시각을 그대로 실행한다는 뜻이 아님 |
| 실행 브랜치·커밋 | 기본 브랜치의 최신 커밋에서 실행 | schedule — GITHUB_SHA / GITHUB_REF |
모든 브랜치에 같은 cron이 생기거나 feature 브랜치의 워크플로 파일이 예약 실행된다는 뜻이 아님 |
| 스케줄 지연 | Actions 고부하 때 지연 가능; 매시 시작 시점이 고부하 시간에 포함 | schedule — “delayed during periods of high loads” |
지연의 최대 분수가 정해졌거나 정각을 피하면 지연이 0이 된다는 뜻이 아님 |
| 대기 작업 유실 | 부하가 충분히 높으면 일부 queued job이 유실될 수 있음 | Scheduled workflows running at unexpected times | 모든 지연 작업이 나중에 반드시 실행된다는 뜻이 아니므로 업무 측 재시도·누락 감지가 필요함 |
| 공개 저장소 비활성 | 저장소 활동이 60일 없으면 scheduled workflow 자동 비활성화 |
schedule — “no repository activity … 60 days” |
비공개 저장소에도 같은 60일 규칙이 적용되거나, 다시 활성화하면 놓친 실행이 소급된다는 뜻이 아님 |
| 전체 workflow run | 최대 35일; 실행·대기·승인 시간 포함 |
Workflow execution limit — Workflow run time | 하나의 GitHub-hosted job이 35일 동안 실행될 수 있다는 뜻이 아님 |
| 환경 승인 대기 | 최대 30일 |
Workflow execution limit — Gate approval time | job 실행 시간 6시간에 30일을 더할 수 있다는 뜻이 아니며 전체 35일 한도에도 포함됨 |
| GitHub-hosted job 실행 | job당 최대 6시간 |
All GitHub-hosted runners — Job execution time | 워크플로 전체가 6시간으로 제한된다는 뜻이 아니며, 6시간 도달 시 해당 job은 종료·실패함 |
| self-hosted job 실행 | job당 최대 5일 |
Self-hosted — Job execution time | GITHUB_TOKEN이 5일 유효하다는 뜻이 아님. 토큰은 job 종료 또는 최대 24시간에 만료될 수 있음 |
| self-hosted 대기 | queue에서 최대 24시간 후 자동 취소 |
Self-hosted — Job queue time | runner에 배정된 뒤 24시간 실행할 수 있다는 뜻이 아니라, 배정 전 대기 한도임 |
| job timeout 기본값 | timeout-minutes 기본 360분 |
jobs.<job_id>.timeout-minutes — “Default: 360” |
모든 작업에 360분을 권장한다는 뜻이 아니며 runner 자체 한도를 넘겨 연장하지 못함 |
| job matrix | workflow run당 최대 256 jobs |
Workflow execution limit — Job Matrix | 256개가 동시에 실행된다는 뜻이 아니며 플랜별 동시 job 한도와 runner 가용성이 별도로 적용됨 |
| 재실행 | workflow run당 최대 50회; 전체·일부 job 재실행 포함 |
Workflow execution limit — Re-run | 실패 작업을 자동으로 50회 재시도한다는 뜻이 아니며 같은 부작용을 반복해도 안전하다는 뜻도 아님 |
| 워크플로 파일 | 파일당 최대 500KB |
Workflow file — Workflow file size | 저장소 전체 .github/workflows 용량 한도나 아티팩트 크기 한도가 아님 |
| Free 동시 job | standard GitHub-hosted runner 총 20, macOS 최대 5 |
Job concurrency limits for GitHub-hosted runners — Free | 한 워크플로가 항상 20개를 즉시 점유하거나 macOS 5개가 총 20개와 별도 추가된다는 뜻이 아님 |
| Pro·Team·Enterprise 동시 job | 각각 총 40·60·500; macOS 최대 5·5·50 |
Job concurrency limits for GitHub-hosted runners | larger runner의 별도 한도나 실제 조직에 승인된 증설분까지 나타내는 값이 아님 |
| GitHub Free 제공량 | private repository용 월 2,000분, artifact storage 500MB, repository별 cache 10GB |
Free use of GitHub Actions — GitHub Free | 공개 저장소 standard runner의 무료 사용 범위와 같은 의미가 아니며, 500MB는 Packages와 공유되고 cache 10GB는 별도임 |
| 무료 분 초기화 | 각 결제 주기 시작 때 월 제공분 초기화 | Free use of GitHub Actions | 남은 분이 다음 달로 이월되거나 초과 사용 기록·비용이 소급 삭제된다는 뜻이 아님 |
| 아티팩트·로그 기본 보존 | 기본 90일 |
Configuring the retention period for GitHub Actions artifacts and logs | 백업 보장 기간이나 삭제 후 복구 가능 기간이 아니며 조직 설정이 더 짧을 수 있음 |
| 보존 기간 조정 범위 | public 1~90일, private 1~400일 |
For public repositories / For private repositories | 기존 아티팩트에 소급 적용되지 않으며 상위 organization·enterprise 제한을 넘을 수 없음 |
조건에 따라 스케줄 방식을 고르는 판단 기준표
| 조건 | 선택 | 이유 |
|---|---|---|
| 몇 분 늦어져도 되고 누락을 다음 주기에서 확인할 수 있음 | schedule + 업무 상태 체크 |
최소 5분 주기는 가능하지만 시작 시각과 실행 자체가 보장되지는 않음 |
| 같은 작업의 중첩 실행이 데이터 충돌을 만들 수 있음 | concurrency 그룹 + 멱등성 키 |
이전 run과 새 run의 동시 변경을 막고, 재실행에도 같은 결과를 유지할 기준이 필요함 |
| 정확한 시각의 실행 또는 누락 없는 트리거가 계약 조건임 | GitHub schedule을 단독 스케줄러로 사용하지 않음 |
공식 문서가 고부하 지연과 queued job 유실 가능성을 명시함 |
| 사람이 실패 뒤 즉시 복구해야 함 | workflow_dispatch 병행 + 실행 전 중복 여부 확인 |
수동 복구 경로를 만들되 자동 run과 겹쳐 같은 변경을 두 번 수행하지 않게 해야 함 |
| 정상 작업 시간이 20분 이내로 정의돼 있음 | timeout-minutes: 20처럼 업무 상한을 명시 |
기본 360분보다 짧은 실패 경계를 두어 hung job의 사용 시간을 제한할 수 있음 |
| 결과 파일을 단기 전달용으로만 씀 | 짧은 retention-days + 필요한 결과만 업로드 |
기본 90일을 그대로 쓰지 않아도 되며 저장량은 시간에 따라 누적 계산됨 |
| 감사·법적 보존이 필요함 | 아티팩트만 믿지 말고 승인된 별도 보존소 사용 | Actions 보존 기간은 public 90일, private 400일 상한이 있고 삭제는 백업과 같지 않음 |
중복과 장기 실행을 제한하는 YAML 골격
아래는 실제 실행 결과가 아니라 공식 구문을 조합한 설정 예시입니다. 17분을 택한 것은 정각 고부하를 피하려는 운영 선택일 뿐, 지연 방지 보장값이 아닙니다. 시간대는 저장소의 독자·운영 지역에 맞는 IANA 이름으로 바꿔야 합니다.
name: daily-report
on:
schedule:
- cron: '17 9 * * *'
timezone: 'Asia/Seoul'
workflow_dispatch:
concurrency:
group: daily-report
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- name: Run report
run: ./scripts/build-report.sh
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: daily-report
path: output/report.json
retention-days: 7
cancel-in-progress: false는 진행 중 run을 자동 취소하지 않는 예시입니다. 새 실행을 우선해야 하는 작업은 true를 검토할 수 있지만, 외부 시스템 변경 도중 취소해도 안전한지 먼저 판단해야 합니다. 제3자 Action 버전은 예시를 그대로 신뢰하기보다 해당 Action의 현재 릴리스와 권한 범위를 별도로 고정해야 합니다.
증상 → 원인 후보 → 확인 → 조치
| 증상 | 원인 후보 | 확인할 항목 | 조치 |
|---|---|---|---|
| 예약 시각보다 늦게 시작함 | 매시 정각을 포함한 Actions 고부하 대기 | cron의 분 필드, run의 예약 시각과 실제 시작 시각 | 업무 허용 오차를 정하고 정각 이외 분으로 옮기되, 최대 지연을 임의로 가정하지 않음 |
| 예약 run 자체가 없음 | 기본 브랜치에 워크플로 파일 없음, 공개 저장소 60일 비활성, 고부하 중 queued job 유실 | default branch 파일, workflow 활성 상태, 저장소 최근 활동, Actions 실행 목록 | 원인별로 파일을 기본 브랜치에 두거나 workflow를 재활성화하고, 업무 데이터에서 누락 주기를 탐지해 수동 복구 |
| 로컬 시각과 다른 시간에 실행됨 | UTC 해석 또는 잘못된 IANA 시간대 | timezone 유무, cron 5개 필드, DST 적용 지역 |
UTC로 환산하거나 명시적 IANA 시간대를 사용하고 DST 경계 날짜의 동작을 설계에 포함 |
| run이 6시간 부근에서 실패함 | GitHub-hosted job execution time 한도 도달 | job별 소요 시간, 대기와 실행 구간, 외부 요청 timeout | 작업을 체크포인트 단위로 나누고 업무상 더 짧은 timeout-minutes와 재개 지점을 설정 |
| 수동 재실행 뒤 결과가 두 번 반영됨 | 자동 run과 수동 run 중첩, 비멱등 쓰기 | 동일 날짜·대상 키의 진행 중 run과 외부 시스템 변경 기록 | concurrency 그룹을 정하고 결과 쓰기에 멱등성 키·중복 검사를 추가 |
| matrix job이 대기열에 오래 머묾 | matrix 크기가 플랜의 동시 job 수보다 큼 | matrix 생성 수, Free 20 등 플랜별 총 동시 job 한도, macOS job 수 | matrix 축을 줄이거나 묶고 max-parallel로 의도한 병렬 폭을 명시 |
| 무료 분이 예상보다 빨리 줄어듦 | private repository의 여러 job·재실행·실패 구간 누적 | 소유자 플랜, runner OS, job별 사용 시간, 재실행 횟수 | 필요 없는 matrix와 재실행을 줄이고 timeout을 설정한 뒤 소유자 기준 사용량을 추적 |
| 아티팩트가 사라짐 | 기본 또는 개별 retention 만료, 상위 조직 정책 | 생성일, repository·organization 보존 설정, retention-days |
복구를 약속하지 말고 다시 생성 가능한지 판단하며 장기 보존 자료는 별도 저장소로 이동 |
| 아티팩트 삭제 후에도 당월 저장 비용이 남음 | 이미 누적된 GB-Hours | 현재 저장량과 billing cycle의 accrued storage 구분 | 삭제 시점 이후 누적만 멈춘다는 전제로 보존 기간·업로드 크기를 앞단에서 줄임 |
운영 전에 고정할 8가지
- 허용 지연과 누락 복구 시간을 수치로 정합니다. GitHub가 제공하지 않는 최대 지연값을 가정하지 않습니다.
- 기본 브랜치의 워크플로 파일을 기준으로 봅니다. 다른 브랜치에서 수정만 해둔 상태는 예약 실행 조건을 충족하지 않습니다.
- 시간대를 명시합니다. UTC를 쓸지 IANA 시간대를 쓸지 정하고 DST가 있는 지역은 전환일을 별도로 다룹니다.
- 업무 시간 상한으로 timeout을 줄입니다. 360분 기본값을 그대로 운영 목표로 사용하지 않습니다.
- 중복 정책을 선택합니다. 이전 run을 취소할지, 끝날 때까지 새 run을 막을지, 같은 결과 쓰기를 어떻게 멱등하게 만들지 정합니다.
- 성공 로그가 아니라 결과 상태를 확인합니다. 대상 날짜의 리포트나 처리 키가 존재하는지 별도 상태로 검사합니다.
- 보존 기간과 저장 위치를 분리합니다. 전달용 artifact와 장기 보관본의 목적을 섞지 않습니다.
- 수동 복구 절차를 문서화합니다.
workflow_dispatch실행 전에 진행 중 run과 이미 반영된 결과를 확인합니다.
정기 실행 결과를 표 형태로 후처리해야 한다면 Google Sheets 자동화의 입력·오류 분리 기준을 함께 볼 수 있습니다. 실행 뒤 이메일 요청과 상태 변화를 추적해야 한다면 이메일 후속 업무의 상태 추적 구조로 이어갈 수 있습니다.
공식 문서에 없는 값과 이번 확인 경계
| 항목 | 판정 | 본문 처리 |
|---|---|---|
| schedule 지연의 최대 시간 | 확인한 공식 문서에 고정 상한 없음 | “최대 수십 분” 같은 수치를 쓰지 않고 지연·유실 가능성만 명시 |
| 정각 이외 분으로 옮겼을 때의 개선율 | 공식 보장값 없음·이번 글에서 미측정 | 특정 분을 쓰면 지연이 획기적으로 줄었다는 완료형을 쓰지 않음 |
| 예시 YAML의 성공·비용 절감 | 미실행·미측정 | 구문 조합 예시로만 제시하고 구축 사례나 검증 결과로 부르지 않음 |
| 모든 실패의 자동 알림 | 단일 기본 보장으로 확인하지 않음 | 취소·runner 미배정·외부 알림 실패를 포함하는 별도 감시가 필요하다고 구분 |
| Free 2,000분의 적용 범위 | private repository의 standard GitHub-hosted runner 제공량 | public repository 또는 larger runner까지 같은 월 한도로 설명하지 않음 |
| 공식 문서 5건 | 2026-09-13 직접 대조 | 본문 표에 원문 항목명과 해석 경계를 함께 기록 |
핵심 결론
GitHub Actions의 예약 자동화는 “5분 간격을 지원한다”와 “정시에 반드시 실행된다”를 분리해야 합니다. GitHub-hosted job의 6시간 한도와 전체 workflow run의 35일 한도도 같은 값이 아닙니다. 운영 기준은 cron 한 줄이 아니라 허용 지연, 누락 탐지, 중복 제어, 업무 timeout, 복구 경로, 보존 기간까지 한 묶음으로 정해야 합니다.