GitLab 파이프라인 스케줄: 매일 밤 AI 영상 작업 실행

GitLab 예약 파이프라인을 매일 밤 실행해 날짜 기반 Idempotency-Key로 AI 영상을 시작하고, 실행 마감보다 긴 작업 타임아웃 안에서 폴링하세요.

읽는 시간 6분Sume
전체 글

GitLab 예약 파이프라인(scheduled pipeline)은 Build > Pipeline schedules에서 정한 cron 패턴에 따라 .gitlab-ci.yml을 실행하며, 작업은 rules: - if: $CI_PIPELINE_SOURCE == "schedule"로 스케줄이 시작한 파이프라인에서만 돌게 할 수 있습니다. 매일 밤 만드는 AI 영상이라면 그 작업이 파이프라인 날짜로 만든 Idempotency-Key로 실행 하나를 시작하고, 마스킹된 CI/CD 변수에서 API 키를 읽고, 실행의 90분 마감보다 길게 잡은 작업 타임아웃 안에서 백오프하며 폴링합니다.

GitLab 관련 내용은 예약된 파이프라인을 비롯해 출처에 나열한 GitLab 문서에서, Sume 관련 내용은 Format 호출하기 (영문), 실행과 결과 (영문), Format 쿡북에서 가져왔습니다. 모두 2026-09-27에 확인했습니다. Sume에는 GitLab 전용 연동이 없으며, 작업이 curl과 jq로 HTTPS를 직접 호출합니다. GitHub에서 릴리스를 계기로 실행하는 같은 흐름은 GitHub Actions: 릴리스 영상 만들기에서 다룹니다.

GitLab에서 예약 파이프라인은 어떻게 만드나요?

프로젝트에서 Build > Pipeline schedules를 선택한 다음 New schedule을 선택하세요. 양식에서 입력하는 항목은 다음과 같습니다.

  • 간격 패턴: 미리 정해진 값이나 임의의 cron 값을 쓸 수 있습니다. 다만 스케줄은 인스턴스의 최대 예약 파이프라인 빈도보다 자주 실행될 수 없습니다.
  • 파이프라인이 실행될 대상 브랜치나 태그.
  • 최대 20개의 입력(inputs)과, 이 스케줄의 파이프라인에만 존재하는 CI/CD 변수. GitLab은 파이프라인 설정에는 변수 대신 입력을 쓰라고 권장합니다.
  • 여러분이 스케줄 소유자가 되며, 파이프라인은 여러분의 권한으로 실행됩니다. 지금 바로 시작하려면 Run을 선택하세요. 수동 실행은 분당 한 번까지 허용됩니다.

API 키는 어디에 두어야 하나요?

YAML에는 절대 두지 말고 프로젝트 CI/CD 변수에 두세요. Sume 문서는 키를 둘 수 있는 곳으로 CI 시크릿 저장소를 꼽습니다. GitLab 18.3부터 Visibility 설정의 기본값은 Masked이며, 작업 로그에서 값을 [MASKED]로 바꿔 표시합니다. 마스킹할 값은 공백 없는 한 줄이어야 하고 8자 이상이어야 합니다. GitLab은 마스킹이 악의적인 사용자로부터 값을 지키는 확실한 방법은 아니라고도 경고합니다. Protect variable을 선택하면 보호된 브랜치나 태그의 파이프라인에서만 변수를 쓸 수 있으므로, 스케줄의 대상은 보호된 브랜치로 지정하세요.

매일 밤 도는 작업은 어떤 모습인가요?

키와 본문은 CI_PIPELINE_CREATED_AT에서 만듭니다. 이 값은 파이프라인이 만들어진 시각으로 ISO 8601 형식이고 기본적으로 UTC이므로, 그 파이프라인 안의 모든 재시도가 같은 요청을 보냅니다. 이미지에는 curl과 jq가 있어야 합니다. 여러 명령이 한 문자열에 함께 들어 있으면 GitLab은 마지막 명령의 결과만 보고하므로, 실패 경로는 모두 명시적인 exit 1에서 끝납니다. 루프는 Sume 쿡북이 엔드포인트를 노출할 수 없는 CI 작업에 권하는 대로 5초에서 60초까지 백오프하며, 반복할 때마다 출력합니다.

nightly-video:
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  timeout: 100 minutes # above Sume's 90-minute run deadline
  retry: 2
  script:
    - |
      DAY="${CI_PIPELINE_CREATED_AT%%T*}" # the pipeline's UTC date, same on every retry
      jq -n --arg day "$DAY" '{input: {day: $day}}' > body.json
      curl -sS -X POST https://api.sume.com/v1/formats/acme/nightly-recap/runs \
        -H "Authorization: Bearer $SUME_API_KEY" -H "Content-Type: application/json" \
        -H "Idempotency-Key: nightly-recap-$DAY" -d @body.json -o run.json
      RUN_ID=$(jq -er .data.id run.json) || { cat run.json; exit 1; }
    - |
      SLEEP=5
      while :; do
        STATUS=$(curl -sS "https://api.sume.com/v1/format-runs/$RUN_ID" \
          -H "Authorization: Bearer $SUME_API_KEY" | jq -r '.data.status // "unknown"')
        echo "$(date -u +%T) $STATUS" # steady output: silent jobs are dropped after an hour
        case "$STATUS" in
          completed) break ;;
          failed|canceled|skipped) exit 1 ;;
        esac
        sleep "$SLEEP"; SLEEP=$(( SLEEP < 60 ? SLEEP * 2 : 60 ))
      done

GitLab 작업은 기다리는 동안 얼마나 오래 실행될 수 있나요?

GitLab이 작업을 먼저 실패 처리하지 않도록 작업 timeout을 Sume 마감보다 길게 설정하세요. 그래도 작업이 멈추면 실행은 계속 진행되며 계속 과금됩니다. 나중에 ID로 실행을 읽으세요. 루프 중에 받는 429나 503은 일시적이므로, 상태를 읽지 못해도 루프를 한 번 더 돌 뿐입니다. 공개 HTTPS 엔드포인트를 운영하고 있다면 communication.webhook_url을 보내고 생성 요청 뒤에 작업을 끝내세요. 실행이 완료되거나 실패하면 Sume가 그곳으로 결과를 POST합니다.

GitLab의 파이프라인 설정 사용자 지정과 YAML 레퍼런스, Sume의 실행과 결과 (영문) 기준, 2026-09-27 확인.
한도값출처
프로젝트 작업 타임아웃기본값 60분. 10분 이상, 한 달 미만GitLab
작업의 timeout 키워드프로젝트 타임아웃보다 길 수는 있지만 러너 타임아웃보다 길 수는 없음GitLab
프로젝트와 러너 타임아웃이 모두 설정된 경우더 낮은 값이 적용됨GitLab
출력이 없는 작업타임아웃과 관계없이 한 시간 뒤 중단됨GitLab
실행 마감created_at으로부터 최대 90분. 그 뒤 failed로 강제 종료Sume
롱폼 영상15분에서 30분 걸리는 작업Sume

작업이 재시도되면 어떻게 되나요?

retry가 없으면 GitLab은 작업을 재시도하지 않습니다. retry: 2를 두면 실패한 작업이 최대 두 번 더 처리되며, 기본적으로 실패 유형을 가리지 않습니다. 재시도마다 같은 키와 본문을 보내므로 Sume는 원래 실행과 idempotency_hit: true를 담아 200으로 응답합니다. 두 번째 실행도, 두 번째 청구도 없으며, 루프는 같은 실행을 이어서 추적합니다. 같은 UTC 날짜에 스케줄을 수동으로 Run해도 그 실행이 재전송됩니다.

새 키가 필요한 경우는 두 가지입니다. failed로 끝난 실행은 그 키에 묶여 있으므로 새 키로 재시도하세요. 그리고 같은 날짜에 일부러 두 번째 영상을 만들려면 nightly-recap-$DAY-v2처럼 직접 올리는 버전을 붙이세요. 키 설계는 AI 영상 API 멱등성 키에서 다룹니다.

출처

관련 글

연동 카테고리의 다른 글

연동 글 전체 보기

작성자 Sume