비동기 함수 재시도

이 문서에서는 실패 시 HTTPS가 아닌 비동기 백그라운드 함수를 요청하여 재시도하는 방법을 설명합니다.

재시도 의미 체계

Cloud Functions는 이벤트 소스에서 전송한 각 이벤트에 대해 이벤트 기반 함수를 최소한 1회 실행하도록 보장합니다. 하지만 기본적으로 함수 호출이 오류 발생으로 종료되면 해당 함수는 다시 호출되지 않으며 이벤트는 삭제됩니다. 이벤트 기반 함수에 재시도를 사용 설정하면 Cloud Functions는 실패한 함수 호출을 성공할 때까지 또는 재시도 기간이 만료할 때까지 다시 시도합니다. 2세대 함수의 경우 24시간 후에 재시도 기간이 만료됩니다. 1세대 함수의 경우 7일 후에 만료됩니다. 새로 생성된 이벤트 기반 함수는 지수 백오프 전략을 사용하여 재시도하며, 최소 백오프는 10초, 최대 백오프는 600초(10분)입니다. 이 정책은 새 함수를 처음 배포할 때 적용됩니다. 함수를 다시 배포하더라도 이 출시 노트에 설명된 변경사항이 적용되기 전에 처음 배포했던 기존 함수에 소급 적용되지 않습니다.

기본값인 함수에 대해 재시도가 사용 설정되지 않은 경우 함수가 항상 성공적으로 실행된 것으로 보고하고 200 OK 응답 코드가 로그에 나타날 수 있습니다. 이것은 함수에 오류가 발생한 경우에도 수행됩니다. 함수에 오류가 발생할 때 이를 명확하게 표시하려면 오류 보고를 적절히 수행해야 합니다.

이벤트 기반 함수를 완료하는 데 실패하는 이유

드문 경우지만 내부 오류로 인해 함수가 조기 종료될 수 있으며 기본값에 따라 함수가 자동으로 재시도되거나 재시도되지 않을 수 있습니다.

보통은 함수 코드 자체에 발생한 오류로 인해 이벤트 기반 함수를 완료하는 데 실패할 수 있습니다. 이러한 문제가 발생할 수 있는 이유는 다음과 같습니다.

  • 함수에 버그가 있으며 런타임에서 예외가 발생합니다.
  • 함수가 서비스 엔드포인트에 도달할 수 없거나 엔드포인트에 도달하려고 시도하는 중에 제한 시간이 초과하였습니다.
  • 예를 들어 매개변수가 유효성 검사에 실패하는 경우 등 함수에서 의도적인 예외가 발생합니다.
  • Node.js로 작성한 함수에서 거부된 프로미스를 반환하거나 null 외의 값을 콜백에 전달합니다.

위와 같은 경우 기본적으로 함수 실행이 중지되고 이벤트가 삭제됩니다. 오류 발생 시 함수를 재시도하려면 '실패 시 재시도' 속성을 설정하여 기본 재시도 정책을 변경하면 됩니다. 그러면 함수가 완료될 때까지 최대 며칠 동안 이벤트가 반복적으로 재시도됩니다.

재시도 사용 설정 및 중지

GCP Console 사용

다음과 같이 GCP Console에서 재시도를 사용 설정하거나 중지할 수 있습니다.

  1. Cloud Platform Console의 Cloud Functions 개요 페이지로 이동합니다.

  2. 함수 만들기를 클릭합니다. 또는 기존 함수를 클릭하여 세부정보 페이지로 이동하고 수정을 클릭합니다.

  3. 함수의 필수 필드를 작성합니다.

  4. 트리거 필드가 Cloud Pub/Sub 또는 Cloud Storage와 같은 이벤트 기반 함수 트리거 유형으로 설정되어 있는지 확인합니다.

  5. 더보기를 클릭하여 고급 설정을 펼칩니다.

  6. 실패 시 재시도 라벨이 지정된 체크박스를 선택하거나 선택 해제합니다.

함수 코드 내에 사용 설정

Firebase용 Cloud Functions를 사용하면 함수 코드 내에 재시도를 사용 설정할 수 있습니다. functions.foo.onBar(myHandler);와 같은 백그라운드 함수에 이 작업을 수행하려면 runWith를 사용하여 오류 정책을 구성합니다.

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

표시된 대로 true를 설정하면 오류 시 함수를 재시도하도록 구성합니다.

권장사항

이 섹션에서는 재시도 사용의 권장사항을 설명합니다.

재시도를 사용하여 일시적인 오류 처리

함수는 성공적으로 실행될 때까지 지속적으로 재시도되므로 재시도를 사용 설정하기 전에 테스트를 통해 버그와 같은 영구적인 오류를 코드에서 제거해야 합니다. 재시도는 불안정한 서비스 엔드포인트 또는 시간 초과와 같이 재시도하면 해결될 가능성이 매우 높은 간헐적이거나 일시적인 실패를 처리하는 데 가장 적합합니다.

무한 재시도 루프를 방지하기 위해 종료 조건 설정

재시도를 사용할 때 함수가 지속적인 루프에 빠지지 않도록 조치를 취하는 것이 좋습니다. 함수 처리가 시작되기 전에 명확하게 정의된 종료 조건을 포함하면 됩니다. 함수가 성공적으로 시작되고 종료 조건을 평가할 수 있는 경우에만 이 방법을 사용할 수 있습니다.

간단하면서도 효과적인 방법은 특정 시간보다 오래된 타임스탬프가 있는 이벤트를 삭제하는 것입니다. 이렇게 하면 지속적으로 실패하거나 예상보다 오래 실패할 경우에 과도하게 많이 실행되는 것을 방지할 수 있습니다.

예를 들어 이 코드 스니펫은 10초보다 오래된 모든 이벤트를 삭제합니다.

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

프로미스와 함께 catch 사용

함수 재시도가 사용 설정되면 처리되지 않은 오류가 재시도를 트리거합니다. 코드에서 재시도를 초래해서는 안 되는 오류가 포착되는지 확인하세요.

수행할 작업의 예는 다음과 같습니다.

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

재시도 가능한 이벤트 기반 함수 멱등성 만들기

재시도할 수 있는 이벤트 기반 함수는 멱등성이 있어야 합니다. 이러한 함수 멱등성을 만들기 위한 일반적인 가이드는 다음과 같습니다.

  • Stripe와 같은 다양한 외부 API를 사용하면 매개변수로 멱등 키를 제공할 수 있습니다. 이러한 API를 사용한다면 이벤트 ID를 멱등 키로 사용해야 합니다.
  • 멱등성이 있으면 재시도해도 안전하므로 최소 1회 전송 시 잘 작동합니다. 따라서 안정적인 코드를 작성하기 위한 일반적인 권장사항은 재시도와 멱등성을 결합하는 것입니다.
  • 코드에 내부적으로 멱등성이 있어야 합니다. 예를 들면 다음과 같습니다.
    • 결과에 변화 없이 변형이 2번 이상 발생할 수 있는지 확인합니다.
    • 상태가 변형되기 전에 트랜잭션에서 데이터베이스 상태를 쿼리합니다.
    • 모든 부가적인 결과에 자체적으로 멱등성이 있는지 확인합니다.
  • 코드에 관계없이 함수 외부에서 트랜잭션 검사를 시행합니다. 예를 들어 특정 이벤트 ID가 이미 처리되었음을 어딘가에 기록하는 상태를 유지합니다.
  • 중복 함수 호출을 대역 외로 처리합니다. 예를 들어 중복 함수가 호출된 후 삭제하는 별도의 삭제 프로세스를 둡니다.

재시도 정책 구성

Cloud 함수의 요구사항에 따라 재시도 정책을 직접 구성할 수 있습니다. 이렇게 하면 다음을 원하는 대로 조합하여 설정할 수 있습니다.

  • 재시도 기간을 7일에서 10분으로 단축합니다.
  • 지수 백오프 재시도 전략의 최소 및 최대 백오프 시간을 변경합니다.
  • 즉시 재시도하도록 재시도 전략을 변경합니다.
  • 데드 레터 주제를 구성합니다.
  • 전송 시도의 최대 및 최소 횟수를 설정합니다.

재시도 정책을 구성하려면 다음 안내를 따르세요.

  1. HTTP 함수를 작성합니다.
  2. Pub/Sub API를 사용하여 Pub/Sub 구독을 만들고 함수의 URL을 대상으로 지정합니다.

Pub/Sub 직접 구성에 대한 자세한 내용은 오류 처리에 관한 Pub/Sub 문서를 참조하세요.