Amazon SQSに関して、勉強したことを残します。
今回はDLQ (Dead Letter Queue)を使って、エラーを起こすメッセージが入った際に、処理が繰り返されるのを防ぐ方法について確認します。
SQSに関する前回の記事はこちら。
DLQが無いと…
前回の記事ではAmazon SQSの基本的な使い方を確認するために、以下のような題材で実装を行いました。
① S3に文章(テキストファイル)格納
↓
② AWS Lambdaを使って各行の文章をSQSへ登録
↓
③ Amazon SQSでメッセージ保持
↓
④ AWS LambdaがSQSからメッセージ受け取って処理
今回も上記の題材を使って、まずエラーが発生した場合の挙動を確認します。
④のConsumer側のLambda関数に以下のような意図的なエラーを発生させるコードを追加するだけです。
import json
def lambda_handler(event, context):
for record in event["Records"]:
msg = json.loads(record["body"])
text = msg["text"]
# この部分を追加 (brokenに対しエラー発生させる)
if "broken" in text:
raise Exception("simulate failure")
word_count = len(text.split())
print(f"Line {msg['line_number']} words: {word_count}")
return {"statusCode": 200}
上記のエラー処理を追加して、実際にbrokenという行を含むファイルをS3に保存すると、Consumer側のCloudWatchに以下のようなエラーメッセージが何度も発生します。
[ERROR] Exception: simulate failure
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 11, in lambda_handler
raise Exception("simulate failure")
また、SQSのコンソールでは使用しているキューの「処理中のメッセージ」が1から減らなくなります。
メッセージが減らないのは、Consumerがメッセージを取得 → エラーのため削除されず → 可視性タイムアウトの時間が経過 → 別のConsumerがメッセージを取得 → エラー の繰り返しになっているためです。
メッセージの処理はキューで設定した「可視性タイムアウト」の間隔で行われるため、CloudWatchの方にエラーメッセージが何度も出ています。
このようにエラーによってメッセージが処理されないと、そのまま何度も処理が繰り返されるため、ファイル処理としては良くありません。
今回のようなお試しであれば、キューのページからメッセージを削除してしまえばよいですが、実際の運用ではそうはいきません。
そこでDLQを設定します。
DLQの導入
まずDLQ用のキューを作成します。
作成方法は通常のキューとほぼ同じで、異なるのはデッドレターキューとして使用できるよう有効化するだけです。(今回は同一アカウント・リージョンのキューであればDLQとして使用できるよう設定)
コンソールでは↓のような選択をしました。
次に元々のテキスト処理用のキューの設定を変更。(下図)
上で作ったキューをDLQとして設定し、何回失敗したらDLQに送るかを「最大受信数」で指定すれば完了です。
これでDLQの導入は完了しました。
先程のようにbrokenの行を含むファイルを入力してしばらく待つと、処理の失敗したメッセージがDLQの方に移動して、テキスト処理用のキューの「処理中のメッセージ」が0になり、DLQ用のキューの「利用可能なメッセージ」が1になります。
DLQのキューを選択し、「メッセージを送受信」の項目からメッセージを確認すると、確かにbrokenの入ったメッセージがDLQに移動しているのが確認できました。
{"bucket": "<テキストを入れたバケット>", "key": "***.txt", "line_number": 1, "text": "broken"}
DLQの使いどころ
実際の運用では、DLQは単なるごみ箱ではなく、失敗した処理を保管して失敗の原因を確認し、再投入するための避難場所のようです。
CloudWatch AlarmでApproximateNumberOfMessagesVisibleをメトリクスとすれば、メッセージが一定数溜まったタイミングで通知を送ることもできます。
通知を元にメッセージの中身からエラーの原因を解析して、処理やデータを修正することになるのかと思います。
まとめ
今回はAmazon SQSに関して、処理が失敗したときの挙動とDLQに関して確認しました。
作った処理の全てが問題なく動くことはあり得ないので、キューを作る時はDLQも併せて作ることが必須と言えそうです。



