はじめに
デプロイされた AWS Lambda を運用する際、エラーの種類に応じて処理方法を分岐させることが、信頼性と効率性を両立する鍵になります。
この記事では、以下の観点から Lambda の失敗処理と再試行戦略を紹介します:
- Lambda の再試行と DLQ の基本
- エラーの種類による処理分岐の考え方
- SQS をイベントソースとした場合の部分的再試行方法
Lambda の再試行と DLQ の基本
Lambdaは非同期イベント(例:S3通知 / SNS / EventBridge)に対して、最大2回まで自動再試行を行います。再試行後も失敗した場合、Dead Letter Queue (DLQ)を設定していれば、失敗イベントを保持することができます。
DLQが未設定の場合、再試行後も失敗すると、そのイベントは完全に失われます
ただ、すべてのエラーを再試行すればよい、というわけではありません。
エラーの種類による処理分岐
Lambda 関数内で発生するエラーは、大きく分けて以下の2種類に分類できます:
エラーの種類 | 例 | 処理方法 | 再試行 | DLQへの格納 |
---|---|---|---|---|
一時的 | 外部APIのタイムアウト・ネットワーク障害 |
throw して Lambda を失敗 |
✅ 自動再試行 | 自動 |
永続的 | バリデーションエラー・データ不備 | DLQ に手動送信 | ❌ しない | 手動 |
永続的エラーの処理ポイント
永続的なエラー(例:必須フィールドの欠落など)は、再試行しても成功する可能性がないため、Lambda 関数内で DLQ に手動送信し、関数自体は成功として終了するのが望ましいです。
これにより、以下のメリットがあります:
- Lambda の再試行による無駄な処理を防止
- DLQ にエラー情報を保存して、後で分析・再処理が可能
- CloudWatch Logs にも記録されるため、監視が容易
Node.jsでのコード例
exports.handler = async (event) => {
for (const record of event.Records) {
const body = JSON.parse(record.body);
try {
await processMessage(body);
} catch (validationErr) {
// 永続的なエラー → 手動でDLQに送信
await sendToDlq(record.body, validationErr);
} catch (err) {
// 一時的なエラー → Lambdaに失敗を通知して再試行
throw new Error(`Temporary error: ${err.message}`);
}
}
};
...
SQS をイベントソースとした場合の部分的再試行
Amazon SQS を Lambda のイベントソースとして使用する場合、複数メッセージをバッチで受信できます。ここで重要なのが、batchItemFailures
を使った部分的再試行です。
部分的再試行を利用すると、失敗したメッセージのみ再試行され、成功したメッセージによる処理が重複して行われることはありません。
batchItemFailures
の使い方
Node.jsの場合でのコード例:
exports.handler = async (event) => {
const batchItemFailures = [];
for (const record of event.Records) {
const body = JSON.parse(record.body);
try {
await processMessage(body);
} catch (err) {
batchItemFailures.push({ itemIdentifier: record.messageId });
}
}
return { batchItemFailures };
};
メリット
- 成功したメッセージは再試行されない
- FIFO キューでも使用可能
- Lambda を失敗させずに、失敗メッセージだけ再試行できる
まとめ
イベントソース | 再試行 | 部分的再試行 | DLQ活用 |
---|---|---|---|
S3通知など | 最大2回(非同期) | ❌ | ✅(Lambdaに設定) |
SQS | 最大5回(イベントソースマッピング) | ✅(batchItemFailures ) |
✅(SQSに設定) |
以上が、Lambdaのエラーハンドリング戦略でした。エラーの種類に応じたハイブリッド戦略で、再試行とDLQの重複を防ぎましょう!