Cloud Scheduler에는 HTTP 및 App Engine 요청에 대한 작업 식별 및 예약 시간 HTTP 헤더가 포함되어 있어 재시도된 실행을 중복 삭제하고 대상 핸들러를 멱등으로 만들 수 있습니다. Cloud Scheduler는 최소 1회 전송을 제공하므로 요청을 중복 삭제하면 제한 시간 또는 일시적인 네트워크 중단이 발생할 때 핸들러 또는 다운스트림 Google Cloud API가 동일한 예약된 실행을 두 번 이상 처리하지 못하게 됩니다.
요청 중복 삭제 작동 방식
동일한 예약 실행에 대한 중복 작업 요청은 다음과 같은 상황에서 발생할 수 있습니다.
- 장기 실행 대상: 대상 서비스가 응답하는 데 작업의 시도 기한(
attemptDeadline)보다 오래 걸리므로 첫 번째 시도가 아직 실행 중인 동안 Cloud Scheduler가 타임아웃되고 작업을 다시 시도합니다. HTTP 대상의 경우attemptDeadline은 기본적으로 3분이며 최대 30분까지 구성할 수 있습니다.attemptDeadline을 대상의 제한 시간과 일치시키거나 실행 시간이 30분을 초과할 수 있는 경우 장기 실행 작업을 비동기식으로 처리합니다. - 네트워크 확인 손실 또는 일시적인 프록시 재시도: 대상이 요청을 수신하고 처리하지만 일시적인 네트워크 중단 또는 프록시 연결 해제로 인해 Cloud Scheduler가 HTTP
2xx응답을 수신하지 못합니다.retryCount를0로 설정하더라도 최소 1회 전송은 일시적인 전송 실패 중에 대상이 중복 요청을 수신할 수 있음을 의미합니다.
작업 핸들러를 멱등성으로 만들고 재시도된 요청을 중복 삭제하려면 Cloud Scheduler가 HTTP 및 App Engine 대상에 대한 요청에 자동으로 포함하는 HTTP 헤더를 사용합니다.
| 헤더 | 설명 |
|---|---|
X-CloudScheduler-JobName |
projects/PROJECT_ID/locations/LOCATION_ID/jobs/JOB_ID의 짧은 작업 식별자(JOB_ID)입니다. |
X-CloudScheduler-ScheduleTime |
|
대상 엔드포인트에 인증 필요
X-CloudScheduler-* 헤더는 인증되지 않으며 모든 호출자가 설정할 수 있습니다. 인증에 이러한 헤더를 사용하지 마세요. 대신 대상 유형에 따라 엔드포인트를 보호합니다.
- HTTP 대상: OIDC 또는 OAuth 토큰을 전송하고 엔드포인트에서 인증을 요구하도록 작업을 구성합니다. 자세한 내용은 HTTP 대상에 인증 사용을 참조하세요.
- App Engine 대상:
app.yaml파일에서login: admin를 설정하고 App Engine 방화벽 규칙을 구성하여 핸들러에 대한 액세스를 제한합니다.
대소문자를 구분하지 않는 헤더 조회 사용
헤더 대문자 표시는 HTTP 버전 및 인프라에 따라 다를 수 있습니다(예: HTTP/1.1의 X-Cloudscheduler-Jobname 또는 Cloud Run과 같은 HTTP/2 환경의 소문자 x-cloudscheduler-jobname 및 x-cloudscheduler-scheduletime). 핸들러에서 항상 대소문자를 구분하지 않는 헤더 조회를 사용합니다.
프로젝트 또는 리전 간 작업 ID 명확화
Cloud Scheduler는 프로젝트 ID 또는 리전 헤더를 자동으로 전송하지 않습니다. 단일 핸들러 엔드포인트는 동일한 JOB_ID를 공유하는 여러 프로젝트 또는 리전에서 요청을 수신할 수 있습니다. 이 경우 HttpTarget.headers, AppEngineHttpTarget.headers 또는 대상 URL 경로 또는 쿼리 매개변수에 프로젝트 ID 또는 리전을 전달하고 중복 삭제 키에 해당 값을 포함합니다.
HTTP 핸들러에서 요청 중복 삭제
핸들러에서 요청 중복 삭제를 구현하기 전에 다음 설정 기본 요건을 완료하세요.
- Cloud Scheduler가
X-CloudScheduler-ScheduleTime헤더를 전송하도록unix-cron형식(예:every 5 minutes대신*/5 * * * *)으로 작업 일정을 구성합니다. - Firestore, Spanner 또는 Memorystore와 같이 트랜잭션 또는 원자적 조건부 쓰기를 지원하는 영구 데이터 스토어를 설정합니다.
컬렉션 또는 테이블(예:
expire_at필드)에 TTL(수명) 정책을 구성하여 작업의 재시도 기간(maxRetryDuration) 후에 이전 중복 삭제 레코드를 삭제합니다. Firestore TTL은 만료된 레코드를 비동기식으로 삭제하며, 일반적으로 24~72시간 이내에 삭제합니다. TTL 정리 전에 재시도에서 비정상 종료된 인스턴스의 실행을 회수할 수 있도록 하려면 임대 만료 타임스탬프(예:lease_expires, 최소한 대상의 요청 제한 시간 및attemptDeadline로 설정)를 저장하고 트랜잭션에서 평가합니다.
HTTP 핸들러에서 예약된 각 실행을 한 번만 처리하려면 다음 단계를 완료합니다.
- 수신 요청 헤더에서
X-CloudScheduler-JobName및X-CloudScheduler-ScheduleTime를 읽고 고정 길이 중복 삭제 키(run_id)로 해싱합니다. - Datastore에서 트랜잭션을 실행하여 중복 삭제 키의 레코드를 확인하고 요청합니다.
- 레코드가 있고
status가completed이면 Cloud Scheduler가 재시도를 중지하도록 작업 로직을 실행하지 않고 HTTP200 OK(또는204 No Content) 상태 코드를 즉시 반환합니다. - 레코드가 있고
status가in_progress이고 임대(lease_expires)가 만료되지 않은 경우, 진행 중인 시도가 실패할 경우 Cloud Scheduler가 재시도 정책을 활성 상태로 유지하도록409 Conflict와 같은 재시도 가능한 오류 상태 코드를 반환합니다. App Engine은503를 시스템 오류로 처리하고retryCount에 반영하지 않고 요청을 재시도하므로 App Engine 대상에서503 Service Unavailable를 반환하지 마세요. - 레코드가 없거나 임대가 만료된 경우
status를in_progress로 설정하고 고유한 시도 ID(attempt_id), 임대 만료 타임스탬프(lease_expires), TTL 만료 타임스탬프(expire_at)를 사용하여 레코드를 작성합니다.
- 레코드가 있고
레코드를 요청한 후 작업 로직을 실행합니다. 트랜잭션에서 레코드를 수정하기 전에 레코드의
attempt_id가 현재 시도와 여전히 일치하는지 확인합니다.- 작업 로직이 성공하면
status를completed로 업데이트하고 HTTP200 OK상태 코드를 반환합니다. - 재시도할 수 있는 오류로 인해 작업 로직이 실패하면
5xx상태 코드를 반환하기 전에 중복 삭제 레코드를 삭제하여 Cloud Scheduler가 임대가 만료될 때까지 기다리지 않고 실행을 재시도할 수 있도록 합니다.
- 작업 로직이 성공하면
HTTP 핸들러 예시
다음 Python 예시(Cloud Run 또는 Cloud Run Functions용)에서는 임대가 있는 Firestore 트랜잭션을 사용하여 실행을 요청하고 재시도된 작업 요청을 중복 삭제합니다.
이 샘플은 프로덕션 레디가 아닙니다. 배포하기 전에 필요에 맞게 검토하고 조정합니다.
Google Cloud API 타겟에 대한 중복 요청 방지
Cloud Scheduler가 HTTP를 통해 Google Cloud API 엔드포인트(*.googleapis.com)를 직접 호출하면 대상 API는 X-CloudScheduler-JobName 및 X-CloudScheduler-ScheduleTime 헤더를 무시합니다. 예를 들어 workflowexecutions.googleapis.com를 호출하여 Workflows 실행을 시작하거나, run.googleapis.com를 호출하여 Cloud Run 작업을 실행하거나, cloudbuild.googleapis.com를 호출하여 Cloud Build 트리거를 실행하면 재시도할 때마다 새 실행이 시작됩니다.
프로덕션 안정성을 위해 상태를 수정하는 가장 다운스트림 서비스에서 멱등성을 적용합니다. 업스트림 레이어에서만 요청을 중복 삭제하면 재시도 기간이 좁아지지만 다운스트림 요청이 성공하고 네트워크를 통해 HTTP 응답이 손실되면 업스트림 호출자가 작업이 완료되었는지 확인할 수 없으며 요청을 다시 시도할 수 있습니다.
Google Cloud API 대상을 예약할 때 중복 실행을 방지하려면 다음 접근 방식을 함께 사용하여 엔드 투 엔드 멱등성을 확보하세요.
멱등 프록시를 통해 요청 라우팅: Cloud Scheduler에서 직접
*.googleapis.com엔드포인트를 호출하는 대신 자체 Cloud Run 서비스 또는 Cloud Run Functions 프록시를 배포하고 해당 프록시를 호출하도록 Cloud Scheduler를 구성합니다. 프록시에서 이 문서의 HTTP 핸들러에서 요청 중복 삭제에 설명된 Python 및 Firestore 원자적 트랜잭션 클레임 패턴을 구현합니다.프록시는
X-CloudScheduler-JobName및X-CloudScheduler-ScheduleTime를 읽고, 재시도된 요청을 중복 삭제하고, 중복 삭제 키를 요청 페이로드의 멱등성 토큰으로 전달합니다(예: Workflows 실행을 시작할 때argument필드).프록시에서 인증을 요구하고(예:
--no-allow-unauthenticated로 배포) OIDC 토큰으로 인증하도록 Cloud Scheduler 작업을 구성합니다. 필요한 최소 Identity and Access Management(IAM) 역할(예: 대상 워크플로의roles/workflows.invoker및 중복 삭제 레코드의roles/datastore.user)만 있는 전용 서비스 계정에서 프록시를 실행합니다.다운스트림 서비스에서 멱등성 적용: 멱등성 토큰을 사용하여 상태 변경 단계를 실행하기 전에 Firestore와 같은 데이터 스토어에서 원자성 또는 트랜잭션 검사를 수행합니다. 서비스에서 호출하는 다운스트림 HTTP 엔드포인트 또는 Cloud Run Functions에 토큰을 전달하여 해당 대상도 재시도를 중복 삭제할 수 있도록 합니다. Workflows, Firestore 트랜잭션, Cloud Run Functions를 사용하는 엔드 투 엔드 예시는 Google Cloud블로그 게시물 Workflows를 사용할 때 API 호출을 정확히 한 번 수행을 참조하세요.