오류와 재시도
오류와 재시도 (Errors and retries)
실패한 요청을 재시도하기 전에 알아둬야 할 점과 오류 처리 방법을 설명해 드릴게요.
출처: 문서
본문
참고 (Note): Docker Sandboxes API와 SDK는 실험적(experimental)이에요. 기능, 인터페이스, 동작이 바뀔 수 있어요.
실패한 요청을 재시도하기 전에, 서비스가 이미 작업을 시작했는지 확인해요. 예를 들어, 애플리케이션이 응답을 잃어도 create 요청은 성공했을 수 있어요. 확인 없이 재시도하면 두 번째 샌드박스가 생길 수 있어요.
오류 응답 읽기 (Read an error response)
API 오류에는 code, message, 그리고 선택적인 타입이 있는 details가 포함돼요. 어떻게 응답할지 code로 결정하세요. 여러 code가 같은 HTTP 상태를 공유하므로, 상태만으로는 실패 원인이 설명되지 않을 수 있어요.
| 코드 (Code) | 어떻게 할까요 |
|---|---|
invalidArgument |
잘못된 요청이나 지원되지 않는 값을 고친 뒤 재시도하세요. |
unauthenticated |
빠졌거나 잘못됐거나 만료된 자격 증명을 대체할 유효한 자격 증명을 얻으세요. |
permissionDenied |
자격 증명에 그 작업에 대한 권한이 있는지 확인하세요. |
notFound |
리소스 이름과 요청 URL을 확인하세요. 클라우드는 서빙하지 않는 라우트에도 이 코드를 반환해요. |
failedPrecondition |
리소스 상태, 필요한 기능, 그리고 If-Match 헤더를 확인하세요. |
resourceExhausted |
할당량, 비율 제한, 요청 크기 제한이 있는지 오류 세부 정보를 확인하세요. |
unimplemented |
백엔드가 요청한 기능을 지원하는지 확인하세요. |
unavailable |
재시도가 작업을 중복하지 않는다는 것을 알게 된 뒤, 지연 후 재시도하세요. |
더 자세한 내용은 오류의 details에 있는 google.rpc.ErrorInfo를 검사하세요(있다면). 그 reason과 domain 필드를 오류 코드와 함께 사용해 특정 원인을 처리하세요. 자유 형식의 메시지 텍스트를 매칭하는 것은 피하고, 인식하지 못하는 detail 타입이 포함된 응답도 처리하세요.
실패한 대기에서 복구하기 (Recover from a failed wait)
API가 HTTP 202를 반환하면 작업이 아직 진행 중이에요. 필요한 상태에 도달하거나 실패할 때까지 리소스를 계속 읽으세요. 리소스의 failure 필드는 초기 요청이 성공한 뒤 발생한 실패를 설명해요.
대기가 타임아웃되거나 취소되어도 작업은 여전히 끝날 수 있어요. 다시 시도하거나 삭제하기 전에 리소스를 검사하세요. SDK 대기 헬퍼는 클라이언트가 받은 마지막 리소스와 모든 실패 세부 정보를 포함하는 WaitError를 보고해요.
클라이언트가 리소스를 받지 못했다면, 원래 요청을 그 멱등성 키(idempotency key)로 재시도해 응답을 복구하세요. "작업을 중복하지 않고 재시도하기"를 보세요.
작업을 중복하지 않고 재시도하기 (Retry without duplicating work)
멱등성 키는 하나의 요청을 식별하므로, 서비스는 같은 요청을 다시 보내면 원래 응답을 반환할 수 있어요. 예를 들어 같은 키로 샌드박스 생성 요청을 반복하면 다른 샌드박스를 만들지 않고 첫 번째 샌드박스를 반환해요.
SDK는 지원되는 각 변경(mutation)에 키를 생성해 줘요(직접 제공하지 않는 한). 직접 API 호출에서는 원래 요청에 Idempotency-Key 헤더를 포함하세요. 키와 정확한 요청(어떤 If-Match 값 포함)을 재시도용으로 보관하세요.
서비스는 받아들여진 결과를 최소 24시간 유지해요. 재생(replay)은 원래 응답을 반환하므로, 이후 리소스를 읽어 최신 상태를 확인해요.
같은 요청을 반복할 때만 같은 키를 사용하세요. 그 키 아래에서 요청을 바꾸면 오류가 나고, 다른 키를 쓰면 또 다른 작업을 제출해요. 지원하는 작업에만 헤더를 보내세요:
| 작업 (Operations) | Idempotency-Key |
|---|---|
| 샌드박스, 이미지, 프로세스, 포트, 스냅샷, 시크릿, 볼륨 만들기 | 선택 사항 (Optional) |
| 스냅샷 복원 (Restore a snapshot) | 선택 사항 (Optional) |
| 샌드박스 시작·멈춤·삭제 (Start, stop, or delete a sandbox) | 선택 사항 (Optional) |
| 시크릿 업데이트 (Update a secret) | 선택 사항 (Optional) |
| 샌드박스 업데이트 (Update a sandbox) | 필수 (Required) |
다른 작업은 멱등성 키를 받지 않아요.
create 요청이 성공했다는 것을 알면, 반환된 리소스를 폴링해 완료를 기다려요. 실패나 잃어버린 응답에서 복구할 때만 재시도하세요. 일시적 실패에는 재시도 사이에 기다리고 시도 횟수를 제한해요.
프로세스 생성도 멱등성 키를 지원해요. 다른 프로세스를 시작하기 전에 같은 키로 생성 응답을 복구하세요. 프로세스 입력, 시그널, 파일 쓰기는 그 키의 적용을 받지 않아요. 그 작업들을 반복하기 전에 결과를 확인하세요.
SDK 재시도 고려하기 (Account for SDK retries)
SDK는 적격한 일시적 실패에 대해 최대 두 번의 추가 시도를 해요. 애플리케이션이 자체 재시도 루프를 관리한다면, 호출에 maxRetries: 0을 설정해 자동 재시도를 끄세요. 두 정책을 결합하면 의도보다 많은 시도가 나올 수 있어요.
호출 내의 자동 재시도는 그 멱등성 키를 재사용해요. 애플리케이션에서 재시도할 때는 호출 옵션에 idempotencyKey로 원래 키를 전달하세요. 그렇지 않으면 별도의 create 호출이 다른 키를 생성해 또 다른 샌드박스를 만들 수 있어요.
재시도 횟수와 경과 시간을 모두 제한하고, 서버 재시도 지연을 존중해요. 비율 제한이 리소스 할당량과 어떻게 다른지는 Request rate limits 문서를 보세요.
동시 변경 처리하기 (Handle concurrent changes)
다른 사람이 수정한 리소스를 바꾸지 않으려면 그 etag를 If-Match 헤더로 보내요. etag는 여러분이 읽은 리소스의 버전을 식별해요. 샌드박스 업데이트와 삭제 같은 작업은 이 헤더를 요구해요. SDK는 사용 중인 리소스 객체에 저장된 etag를 보내요.
직접 API 요청에서는 etag를 반환된 그대로(따옴표 포함) 전달하세요. 필수 헤더가 없으면 HTTP 428, 오래된 etag면 HTTP 412를 반환해요.
etag가 오래됐다면 리소스를 다시 읽고 변경이 여전히 적절한지 결정하세요. SDK에서는 다음 작업에 refresh()가 반환한 객체를 사용하세요. 원래 객체는 여전히 옛 etag를 가져요. 업데이트된 etag로 요청할 때는 다른 멱등성 키를 사용하세요.
명령 결과 확인하기 (Check command results)
API 요청은 실행한 명령이 실패해도 성공할 수 있어요. 명령 결과의 종료 코드와 출력을 요청·대기 오류와 별도로 확인하세요. 0이 아닌 종료 코드는 명령 실패를 알려줘요.
명령 타임아웃 설정하기 (Set a timeout for commands)
processes.run()이 명령을 기다리는 시간을 제한하려면 두 번째 인자에 timeoutMs를 전달해요. 예를 들어 sandbox.processes.run(input, { timeoutMs: 300_000 })는 최대 5분을 기다려요. 타임아웃이나 취소는 로컬 대기를 멈춰요. 샌드박스 안의 프로세스를 죽이지는 않아요.
timeoutMs가 없으면 전체 run에 타임아웃이 없어요. 프로세스를 만들고 출력을 읽는 개별 요청은 30초 타임아웃이 있어요.
더 알아보기 (Learn more)
관련 문서와 심화 내용은 원문을 참고해 주세요.