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 ランタイムで out-of-memory エラーやプロセスクラッシュなど、関数コード外のエラーが発生した場合。

  • 無効なチェックポイントトークンのエラー – チェックポイントトークンが無効になった場合、通常はサービス側の状態の変化が原因です。

次の表で、SDK がこれらのシナリオを処理する方法について説明します。

シナリオ どうなるのか 計測への影響
耐久性のあるハンドラー外のランタイムエラー (OOM、タイムアウト、クラッシュ) Lambda は呼び出しを自動的に再試行します。SDK は最後のチェックポイントからリプレイし、完了したステップをスキップします。 エラーペイロードサイズ + 再試行ごとに 1 回のオペレーション
CheckpointDurableExecution / GetDurableExecutionState APIs の呼び出し時のサービスエラー (5xx) または タイムアウト Lambda は呼び出しを自動的に再試行します。SDK は最後のチェックポイントから再生されます。 エラーペイロードサイズ + 再試行ごとに 1 回のオペレーション
CheckpointDurableExecution / GetDurableExecutionState APIs の呼び出し時のスロットリング (429) または無効なチェックポイントトークン Lambda はエクスポネンシャルバックオフを使用して呼び出しを自動的に再試行します。SDK は最後のチェックポイントから再生されます。 エラーペイロードサイズ + 再試行ごとに 1 回のオペレーション
CheckpointDurableExecution / GetDurableExecutionState APIs の場合のクライアントエラー (4xx、ただし 429 と無効なトークンを除く) SDK は実行を FAILED としてマークします。エラーは永続的な問題を示しているため、自動再試行は行われません。 エラーペイロードサイズ

バックエンドの再試行ではエクスポネンシャルバックオフを使用し、関数が成功するか、実行タイムアウトに達するまで続行します。リプレイ中、SDK は完了したチェックポイントをスキップし、最後に成功した操作の実行を続行し、関数が完了した作業を再実行しないようにします。

再試行のベストプラクティス

再試行戦略を設定するときは、次のベストプラクティスに従ってください。

  • 明示的な再試行戦略を設定する – 本番環境でデフォルトの再試行動作に依存しないでください。ユースケースに適した最大試行回数とバックオフ間隔を使用して、明示的な再試行戦略を設定します。

  • 条件付き再試行を使用する – 一時的なエラー (レート制限、タイムアウト) のみを再試行し、永続的なエラー (検証エラー、未検出) ではフェイルファストする shouldRetry ロジックを実装します。

  • 適切な最大試行回数を設定する – 回復性と実行時間のバランスを取ります。再試行回数が多すぎると障害検出が遅れる可能性がありますが、少なすぎると不要な障害が発生する可能性があります。

  • エクスポネンシャルバックオフを使用する – エクスポネンシャルバックオフは、ダウンストリームサービスの負荷を軽減し、一時的な障害から回復できる可能性を高めます。

  • エラーが発生しやすいコードをステップでラップする – ステップ外のコードを自動的に再試行することはできません。外部 API コール、データベースクエリ、その他のエラーが発生しやすい操作を再試行戦略でステップごとにラップします。

  • 再試行メトリクスをモニタリングする – Amazon CloudWatch でステップ再試行操作と実行失敗を追跡して、パターンを特定し、再試行戦略を最適化します。