背景
やりたいこと
以下のようなアーキテクチャが実現できるか考えてみました。
- SQSキューにメッセージが送信されたらLambdaを起動したい。
- LambdaはDynamoDBにアクセスする。
- DynamoDBのキャパシティユニットを一定に抑えるためにLambdaの同時実行数を制限したい。
- 同時実行数の制限によって処理されなかったSQSメッセージは元のSQSキューに戻し、Lambdaの同時実行数が減ったら改めて処理したい。
- プログラムのエラーによりLambdaで処理できなかったSQSメッセージはデッドレターキューに転送したい。
関係するLambdaの機能
このアーキテクチャの実現にLambdaの以下の機能が利用できます。
Lambdaの関数レベルの同時実行数の管理
LambdaのイベントソースとしてSQSを使う
先日、AWS LambdaでSQSをイベントソースとしてサポートすることが発表されました。
詳しくはクラスメソッドさんの記事を参照してください。
疑問
同時実行数の制限によってLambdaの起動に失敗した場合、トリガーとなったSQSメッセージの受信数はカウントされてしまうのでしょうか。
もしそうなら
- プログラムのエラーによりLambdaで処理できなかったSQSメッセージはデッドレターキューに転送したい。
の要件でデッドレターキューを設定しているため、同時実行数の制限によるLambdaの起動失敗を繰り返した結果、SQSメッセージがデッドレターキューに転送されることが考えられます。よって
- 同時実行数の制限によって処理されなかったSQSメッセージは元のSQSキューに戻し、Lambdaの同時実行数が減ったら改めて処理したい。
の要件を満たすことはできません。
検証
同時実行数の制限によってLambdaの起動に失敗した場合、トリガーとなったSQSメッセージの受信数がカウントされるのか、検証してみました。
検証環境の構築
SQS
sample
とsample-dead
という2個のキューを用意します。
またsample
キューはデッドレターキュー
をsample-dead
に、最大受信数
(デッドレターキューに送信されるまでにメッセージを受信できる最大回数)を1
に設定します。
Lambda
sample
という関数を作成し、sample
キューをイベントソースとして指定します。
また関数の同時実行数を0にします。これによりこのLambdaの起動は全て制限されます。
メッセージの送信
sample
キューに対してメッセージを送信します。
送信直後、すぐにメッセージが処理中のメッセージ
に移動しました。Lambdaのイベントソースとしてメッセージが受信されたことがわかります。しかし、関数の同時実行数は0のため、メッセージがLambdaに渡されることはありません。
しばらくするとメッセージがsample-dead
キューに移動しました。同時実行数の制限によってLambdaの起動に失敗した場合でも、トリガーとなったSQSメッセージの受信数はカウントされ、閾値を超えるとデットレターキューに転送されることがわかりました。
結論
同時実行数の制限によってLambdaの起動に失敗した場合でも、トリガーとなったSQSメッセージの受信数はカウントされるがわかりました。よってSQSをイベントソースとするLambdaに同時実行数の制限を設定しただけでは
- 同時実行数の制限によって処理されなかったSQSメッセージは元のSQSキューに戻し、Lambdaの同時実行数が減ったら改めて処理したい。
- プログラムのエラーによりLambdaで処理できなかったSQSメッセージはデッドレターキューに転送したい。
の2つの要件を同時に満たせないことがわかりました。