はじめに
Lambda を呼び出す方法の一つとして、SQS をトリガーにする構成は非常によく使われるベストプラクティスの一つだと思います。
本記事では、その実装時にAWS歴の浅い筆者が見落としていた注意点について、備忘も兼ねてまとめます。
何に注意すべきか
結論から言うと、バッチサイズを複数指定している場合のエラーハンドリングです。
SQS をトリガーにした Lambda では、batchSize を 2 以上に設定すると 1 回の実行で複数のメッセージを受け取ることがあります。
このとき 「部分的なバッチレスポンス(Partial Batch Response)」を有効にしていない場合、以下の挙動になります。
バッチ内で 1 件でもエラーが発生すると
- すべてのメッセージが失敗扱い
- 正常に処理できたメッセージも再試行される
これが意図した挙動でない場合は、対策が必要でしょう。
部分的なバッチレスポンスとは
部分的なバッチレスポンスを有効にすると、Lambda 側で 「どのメッセージが失敗したか」を明示的に返せるようになります。
- 成功したメッセージ → 再試行されない
- 失敗したメッセージ → 再試行される
という、より細かい制御が可能になります。
設定方法
CDK
someLambdaFunction.addEventSource(
new lambdaEventSources.SqsEventSource(someQueue, {
batchSize: 10,
maxBatchingWindow: cdk.Duration.seconds(30),
// 部分的なバッチレスポンスを有効化
reportBatchItemFailures: true,
})
);
マネコン
- AWS Lambda コンソールを開き、対象の関数を選択する
- 「設定」タブ → 左メニューから「トリガー」を選択する
- 対象の SQS を選択し、「編集」をクリックする
- 「バッチ項目の失敗を報告する (Report batch item failures)」 にチェックを入れる
Lambda 側のコード例(TypeScript)
例:失敗したメッセージのみ再試行させる
import { SQSEvent, SQSBatchResponse } from 'aws-lambda';
export const handler = async (
event: SQSEvent
): Promise<SQSBatchResponse> => {
const batchItemFailures: { itemIdentifier: string }[] = [];
for (const record of event.Records) {
try {
const body = JSON.parse(record.body);
// 何らかの処理
console.log('processing:', body);
} catch (error) {
console.error('failed:', record.messageId, error);
// 失敗したメッセージIDを返す
batchItemFailures.push({
itemIdentifier: record.messageId,
});
}
}
return {
batchItemFailures,
};
};
このようにbatchItemFailuresに失敗したmessageIdのみ格納をして返すことで、正常に処理できたメッセージは再実行されなくなります。
まとめ
- SQS × Lambda で batchSize > 1 の場合は注意
- 部分的なバッチレスポンスを有効にしないと、1件の失敗で全件再試行される
- CDK 側の設定 + Lambda 側のレスポンス実装の両方が必要
参考
- https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/lambda-event-filtering-partial-batch-responses-for-sqs/best-practices-partial-batch-responses.html
- https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/lambda-event-filtering-partial-batch-responses-for-sqs/benefits-partial-batch-responses.html
