Lambda 지속성 함수 재시도 - AWS Lambda

Lambda 지속성 함수 재시도

지속성 함수는 일시적 실패에 대한 애플리케이션의 복원력을 갖추는 자동 재시도 기능을 제공합니다. SDK는 비즈니스 로직 실패에 대한 단계 재시도와 인프라 실패에 대한 백엔드 재시도라는 2가지 수준에서 재시도를 처리합니다.

단계 재시도

단계 내에 발견되지 않은 예외가 발생하면 SDK는 구성된 재시도 전략에 따라 단계를 자동으로 재시도합니다. 단계 재시도는 SDK가 실행을 일시 중지하고 나중에 진행 상황 손실 없이 재개할 수 있도록 하는 체크포인트가 지정된 작업입니다.

단계 재시도 동작

다음 표에서는 SDK가 단계 내에서 예외를 처리하는 방법을 설명합니다.

시나리오 발생한 상황 영향 측정
단계 내 예외 발생(재시도 횟수가 남아 있음) SDK는 재시도를 위해 체크포인트를 생성하고 함수를 일시 중지합니다. 다음 간접 호출에서 단계는 백오프 지연이 구성된 상태에서 재시도합니다. 작업 1개 + 오류 페이로드 크기
단계 내 예외 발생(재시도 횟수가 남아 있지 않음) 단계가 실패하고 예외가 발생합니다. 핸들러 코드가 이 예외를 포착하지 못하면 전체 실행이 실패합니다. 작업 1개 + 오류 페이로드 크기

단계에 재시도가 필요한 경우 SDK는 재시도 상태에 체크포인트를 지정하고 실행 중인 다른 작업이 없는 경우 Lambda 간접 호출을 종료합니다. 이를 통해 SDK는 컴퓨팅 리소스를 소비하지 않고 백오프 지연을 구현할 수 있습니다. 백오프 기간이 지나면 함수가 자동으로 재개됩니다.

단계 재시도 전략 구성

단계에서 실패를 처리하는 방식을 제어하도록 재시도 전략을 구성합니다. 최대 시도 횟수, 백오프 간격 및 재시도 조건을 지정할 수 있습니다.

다음은 최대 시도 횟수가 포함된 지수 백오프입니다.

TypeScript
const result = await context.step('call-api', async () => { const response = await fetch('https://api.example.com/data'); if (!response.ok) throw new Error(`API error: ${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 5) { return { shouldRetry: false }; } // Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) const delay = Math.min(2 * Math.pow(2, attemptCount - 1), 300); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 5: return {'should_retry': False} # Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) delay = min(2 * (2 ** (attempt_count - 1)), 300) return {'should_retry': True, 'delay': delay} result = context.step( lambda _: call_external_api(), name='call-api', config=StepConfig(retry_strategy=retry_strategy) )

다음은 고정 간격 백오프입니다.

TypeScript
const orders = await context.step('query-orders', async () => { return await queryDatabase(event.userId); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 3) { return { shouldRetry: false }; } return { shouldRetry: true, delay: { seconds: 5 } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 3: return {'should_retry': False} return {'should_retry': True, 'delay': 5} orders = context.step( lambda _: query_database(event['userId']), name='query-orders', config=StepConfig(retry_strategy=retry_strategy) )

다음은 조건부 재시도입니다(특정 오류만 재시도).

TypeScript
const result = await context.step('call-rate-limited-api', async () => { const response = await fetch('https://api.example.com/data'); if (response.status === 429) throw new Error('RATE_LIMIT'); if (response.status === 504) throw new Error('TIMEOUT'); if (!response.ok) throw new Error(`API_ERROR_${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { // Only retry rate limits and timeouts const isRetryable = error.message === 'RATE_LIMIT' || error.message === 'TIMEOUT'; if (!isRetryable || attemptCount >= 3) { return { shouldRetry: false }; } // Exponential backoff: 1s, 2s, 4s (capped at 30s) const delay = Math.min(Math.pow(2, attemptCount - 1), 30); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): # Only retry rate limits and timeouts is_retryable = str(error) in ['RATE_LIMIT', 'TIMEOUT'] if not is_retryable or attempt_count >= 3: return {'should_retry': False} # Exponential backoff: 1s, 2s, 4s (capped at 30s) delay = min(2 ** (attempt_count - 1), 30) return {'should_retry': True, 'delay': delay} result = context.step( lambda _: call_rate_limited_api(), name='call-rate-limited-api', config=StepConfig(retry_strategy=retry_strategy) )

재시도를 비활성화합니다.

TypeScript
const isDuplicate = await context.step('check-duplicate', async () => { return await checkIfOrderExists(event.orderId); }, { retryStrategy: () => ({ shouldRetry: false }) });
Python
is_duplicate = context.step( lambda _: check_if_order_exists(event['orderId']), name='check-duplicate', config=StepConfig( retry_strategy=lambda error, attempt: {'should_retry': False} ) )

재시도 전략에서 shouldRetry: false가 반환되면 재시도 없이 단계가 즉시 실패하게 됩니다. 멱등성 검사 또는 안전하게 반복할 수 없는 부가 효과가 있는 작업과 같이 재시도해서는 안 되는 작업에 사용합니다.

단계 외부의 예외

핸들러 코드에서 발견되지 않은 예외가 발생하지만 단계에서 벗어난 경우 SDK는 실행을 실패로 표시합니다. 이를 통해 애플리케이션 로직의 오류가 올바르게 파악 및 보고됩니다.

시나리오 발생한 상황 영향 측정
임의 단계 외부의 핸들러 코드에서 예외 발생 SDK는 실행을 FAILED로 표시하고 오류를 반환합니다. 예외는 자동으로 재시도되지 않습니다. 오류 페이로드 크기

오류가 발생하기 쉬운 코드에 자동 재시도를 활성화하려면 재시도 전략을 통해 단계로 래핑합니다. 단계는 구성 가능한 백오프로 자동 재시도를 제공하는 반면, 단계 외부의 코드는 즉시 실패합니다.

백엔드 재시도

백엔드 재시도는 Lambda에서 인프라 실패, 런타임 오류가 발생하거나 SDK가 지속성 실행 서비스와 통신할 수 없는 경우에 발생합니다. Lambda는 이러한 실패를 자동으로 재시도하여 지속성 함수가 일시적인 인프라 문제로부터 복구될 수 있도록 합니다.

백엔드 재시도 시나리오

다음 시나리오에서 Lambda는 함수를 자동으로 재시도합니다.

  • 내부 서비스 오류 - Lambda 또는 지속성 실행 서비스가 5xx 오류를 반환하여 일시적인 서비스 문제를 나타내는 경우.

  • 스로틀링 - 동시성 제한 또는 서비스 할당량으로 인해 함수가 스로틀링되는 경우.

  • 제한 시간 초과 - 제한 시간 내에 SDK가 지속성 실행 서비스에 연결할 수 없는 경우.

  • 샌드박스 초기화 실패 - Lambda가 실행 환경을 초기화할 수 없는 경우.

  • 런타임 오류 - Lambda 런타임에서 메모리 부족 오류 또는 프로세스 충돌과 같은 함수 코드 외부의 오류가 발생하는 경우.

  • 유효하지 않은 체크포인트 토큰 오류 - 일반적으로 서비스 측 상태 변경으로 인해 체크포인트 토큰이 더 이상 유효하지 않은 경우.

다음 표는 SDK에서 이러한 시나리오에 어떻게 대처하는지 설명합니다.

시나리오 발생한 상황 영향 측정
지속성 핸들러 외부의 런타임 오류(OOM, 제한 시간 초과, 충돌) Lambda는 호출을 자동으로 재시도합니다. SDK는 마지막 체크포인트에서 재생되고, 완료된 단계를 건너뜁니다. 오류 페이로드 크기 + 재시도당 작업 1개
CheckpointDurableExecution/GetDurableExecutionState API를 호출할 때 서비스 오류(5xx) 또는 제한 시간 초과 Lambda는 호출을 자동으로 재시도합니다. SDK는 마지막 체크포인트에서 재생됩니다. 오류 페이로드 크기 + 재시도당 작업 1개
CheckpointDurableExecution/GetDurableExecutionState API를 호출할 때 스로틀링(429) 또는 잘못된 체크포인트 토큰 Lambda는 지수 백오프를 포함한 간접 호출을 자동으로 재시도합니다. SDK는 마지막 체크포인트에서 재생됩니다. 오류 페이로드 크기 + 재시도당 작업 1개
CheckpointDurableExecution/GetDurableExecutionState API에서 클라이언트 오류(4xx, 429 및 잘못된 토큰 제외) SDK는 실행을 FAILED로 표시합니다. 오류가 영구적인 문제를 나타내므로 자동 재시도는 발생하지 않습니다. 오류 페이로드 크기

백엔드 재시도는 지수 백오프를 사용하고 함수가 성공하거나 실행 제한 시간에 도달할 때까지 계속합니다. 재생 중에 SDK는 함수가 완료된 작업을 다시 실행하지 않도록 완료된 체크포인트를 건너뛰고 마지막으로 성공한 작업에서 계속 실행합니다.

재시도 모범 사례

재시도 전략을 구성할 때 다음 모범 사례를 따릅니다.

  • 명시적인 재시도 전략 구성 - 프로덕션 환경에서 기본 재시도 동작에 의존하지 않습니다. 사용 사례에 적합한 최대 시도 횟수와 백오프 간격으로 명시적 재시도 전략을 구성합니다.

  • 조건부 재시도 사용 - 일시적 오류(속도 제한, 제한 시간 초과)만 재시도하고 영구적 오류(검증 실패, 찾을 수 없음) 시에는 빠르게 실패하는 shouldRetry 로직을 구현합니다.

  • 적절한 최대 시도 횟수 설정 - 복원력과 실행 시간 사이의 균형을 맞춥니다. 재시도 횟수가 너무 많으면 실패 감지가 지연되는 반면, 재시도 횟수가 너무 적으면 불필요한 실패가 발생할 수 있습니다.

  • 지수 백오프 사용 - 지수 백오프는 다운스트림 서비스의 부하를 줄이고 일시적 실패로부터 복구할 가능성을 높입니다.

  • 단계에서 오류가 발생하기 쉬운 코드 래핑 - 단계 외부의 코드는 자동으로 재시도할 수 없습니다. 재시도 전략을 사용하여 외부 API 호출, 데이터베이스 쿼리 및 기타 오류가 발생하기 쉬운 작업을 단계별로 래핑합니다.

  • 재시도 지표 모니터링 - Amazon CloudWatch에서 단계 재시도 작업 및 실행 실패를 추적하여 패턴을 식별하고 재시도 전략을 최적화합니다.