2023年6月8日にリリースされた Amazon SQS の新しい API 3種類によって,Amazon SQS のデッドレターキュー (DLQ: Dead Letter Queue) に移動されたメッセージを "元のキュー" や "別のキュー" に戻す「DLQ 再処理」を AWS CLI / AWS SDK などから実行できるようになる.今まではマネジメントコンソールでのみ使えていたけど,今後はアプリケーションからも実行できるため,例えば「リカバリ処理」の自動化などに活用できて良さそう❗️
- StartMessageMoveTask
- CancelMessageMoveTask
- ListMessageMoveTasks
さっそく AWS CLI で検証してみた✌️
構成
今回は以下のように3つの Amazon SQS キューを作った🎲
main-queue
: ビジネスロジックで使うキューmain-queue-dlq
: ビジネスロジックにエラーが繰り返し発生したときなどにメッセージを移動するデッドレターキューrecovery-queue
: リカバリ処理用のキュー
1. main-queue にメッセージを送信する
まず AWS CLI を使って main-queue
にメッセージを5件送信する.メッセージ本文は適当に messageA
のようにしておいた.
$ MAIN_QUEUE=https://sqs.ap-northeast-1.amazonaws.com/123456789012/main-queue $ aws sqs send-message --queue-url ${MAIN_QUEUE} --message-body messageA $ aws sqs send-message --queue-url ${MAIN_QUEUE} --message-body messageB $ aws sqs send-message --queue-url ${MAIN_QUEUE} --message-body messageC $ aws sqs send-message --queue-url ${MAIN_QUEUE} --message-body messageD $ aws sqs send-message --queue-url ${MAIN_QUEUE} --message-body messageE $ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "5" } }
2. main-queue から main-queue-dlq にメッセージを移動させる
次にメッセージを繰り返し取得しながら main-queue-dlq
に移動させる.
# メッセージ件数が少ないと1回で全件取得できない場合もある # https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html $ aws sqs receive-message --queue-url ${MAIN_QUEUE} --max-number-of-messages 10 | jq '.Messages[] | del(.ReceiptHandle)' { "MessageId": "c20308ff-46da-4a02-86cd-219dcf6d5511", "MD5OfBody": "1c8dcdcdaa1600f013e3e15fc4f95d29", "Body": "messageA" } { "MessageId": "cd32e238-ea25-4274-a06a-0cdd7dbc2be4", "MD5OfBody": "8c036043f4dd0bbe092697b126321081", "Body": "messageB" } { "MessageId": "71296c42-02c2-4327-9f2e-de87d2aaeb6a", "MD5OfBody": "be57b336bfd78dd780ed85564672e003", "Body": "messageC" } { "MessageId": "341490cc-7bcc-49e5-808f-8c04f957b7ab", "MD5OfBody": "1430d0d674dc41d3f7710cab7881d685", "Body": "messageD" } { "MessageId": "ebbab43e-262a-4711-95c4-c87ba03fc088", "MD5OfBody": "df4f6feddd75cebc20548e6750427ee0", "Body": "messageE" }
最大受信数に達したため main-queue
のメッセージ件数は0件になった.
$ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "0" } }
3. main-queue-dlq のメッセージを確認する
期待通りに main-queue-dlq
のメッセージ件数が5件になっている👌
そして,デッドレターキューに移動されても MessageId
は同じになる.もちろん MD5OfBody
も同じ👀
$ MAIN_QUEUE_DLQ=https://sqs.ap-northeast-1.amazonaws.com/123456789012/main-queue-dlq $ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE_DLQ} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "5" } } $ aws sqs receive-message --queue-url ${MAIN_QUEUE_DLQ} --max-number-of-messages 10 | jq '.Messages[] | del(.ReceiptHandle)' { "MessageId": "c20308ff-46da-4a02-86cd-219dcf6d5511", "MD5OfBody": "1c8dcdcdaa1600f013e3e15fc4f95d29", "Body": "messageA" } { "MessageId": "cd32e238-ea25-4274-a06a-0cdd7dbc2be4", "MD5OfBody": "8c036043f4dd0bbe092697b126321081", "Body": "messageB" } { "MessageId": "71296c42-02c2-4327-9f2e-de87d2aaeb6a", "MD5OfBody": "be57b336bfd78dd780ed85564672e003", "Body": "messageC" } { "MessageId": "341490cc-7bcc-49e5-808f-8c04f957b7ab", "MD5OfBody": "1430d0d674dc41d3f7710cab7881d685", "Body": "messageD" } { "MessageId": "ebbab43e-262a-4711-95c4-c87ba03fc088", "MD5OfBody": "df4f6feddd75cebc20548e6750427ee0", "Body": "messageE" }
4. "元のキュー" に DLQ 再処理を行う
さっそく aws sqs start-message-move-task
コマンドを使って DLQ 再処理を行う.今回は "元のキュー" にメッセージを戻すため,指定するオプションは --source-arn
のみ.また今回は --max-number-of-messages-per-second
を指定して,1秒間に1メッセージを戻す(デフォルトだと自動的に最適化される).レスポンスの TaskHandle
には Base64 でエンコードされた再処理情報が入る(今回はマスキングした).
$ MAIN_QUEUE_DLQ_ARN=arn:aws:sqs:ap-northeast-1:123456789012:main-queue-dlq $ aws sqs start-message-move-task --source-arn ${MAIN_QUEUE_DLQ_ARN} --max-number-of-messages-per-second 1 { "TaskHandle": "XXXXX" }
期待通りに main-queue-dlq
のメッセージ件数が0件になって,main-queue
のメッセージ件数が5件になった👌
$ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE_DLQ} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "0" } } $ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "5" } }
注意点は DLQ 再処理を行うと異なる MessageId
になるところ(別メッセージとして再度送信されたイメージ).特にアプリケーション側で「冪等性」を考慮するときは MD5OfBody
と組み合わせて同一性を確認すると良さそう❗️
$ aws sqs receive-message --queue-url ${MAIN_QUEUE} --max-number-of-messages 10 | jq '.Messages[] | del(.ReceiptHandle)' { "MessageId": "0533eee6-3aa6-4ec9-8d3a-c66672933886", "MD5OfBody": "1c8dcdcdaa1600f013e3e15fc4f95d29", "Body": "messageA" } { "MessageId": "10ee8c32-642a-4b16-88d5-9411fa71ecf5", "MD5OfBody": "8c036043f4dd0bbe092697b126321081", "Body": "messageB" } { "MessageId": "8842fc6e-3098-4d34-825c-661d9c2b34d5", "MD5OfBody": "be57b336bfd78dd780ed85564672e003", "Body": "messageC" } { "MessageId": "86a51a9b-2c02-486a-85bd-6eca74823995", "MD5OfBody": "1430d0d674dc41d3f7710cab7881d685", "Body": "messageD" } { "MessageId": "69114df1-0062-49a6-b22e-4b6181299505", "MD5OfBody": "df4f6feddd75cebc20548e6750427ee0", "Body": "messageE" }
5. "別のキュー" に DLQ 再処理を行う
もう一度 main-queue-dlq
のメッセージ件数に5件にして,今度は "別のキュー" にメッセージを戻す.その場合は aws sqs start-message-move-task
コマンドに追加で --destination-arn
オプションを指定する.あとは同じ❗️
$ MAIN_QUEUE_DLQ_ARN=arn:aws:sqs:ap-northeast-1:123456789012:main-queue-dlq $ RECOVERY_QUEUE=https://sqs.ap-northeast-1.amazonaws.com/123456789012/recovery-queue $ RECOVERY_QUEUE_ARN=arn:aws:sqs:ap-northeast-1:123456789012:recovery-queue $ aws sqs start-message-move-task --source-arn ${MAIN_QUEUE_DLQ_ARN} --destination-arn ${RECOVERY_QUEUE_ARN} --max-number-of-messages-per-second 1 { "TaskHandle": "XXXXX" }
期待通りに recovery-queue
のメッセージ件数が5件になっている👌
$ aws sqs get-queue-attributes --queue-url ${RECOVERY_QUEUE} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "5" } }
さらに aws sqs list-message-move-tasks
コマンドを使うと DLQ 再処理の状況を確認できる.今回は実行後に確認したため COMPLETED
になっていた.
$ aws sqs list-message-move-tasks --source-arn ${MAIN_QUEUE_DLQ_ARN} { "Results": [ { "Status": "COMPLETED", "SourceArn": "arn:aws:sqs:ap-northeast-1:123456789012:main-queue-dlq", "MaxNumberOfMessagesPerSecond": 1, "ApproximateNumberOfMessagesMoved": 5, "ApproximateNumberOfMessagesToMove": 5, "StartedTimestamp": 1686875002170 } ] }
6. DLQ 再処理をキャンセルする
最後に aws sqs cancel-message-move-task
コマンドを試すためにメッセージを30件まで増やして main-queue-dlq
に移動した.
$ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE_DLQ} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "30" } }
そして aws sqs start-message-move-task
コマンドを実行した直後に aws sqs cancel-message-move-task
コマンドを実行した.そのときに TaskHandle
を指定する必要がある.
$ aws sqs start-message-move-task --source-arn ${MAIN_QUEUE_DLQ_ARN} --max-number-of-messages-per-second 1 { "TaskHandle": "XXXXX" } $ aws sqs cancel-message-move-task --task-handle XXXXX { "ApproximateNumberOfMessagesMoved": 1 }
DLQ 再処理のキャンセル中に aws sqs list-message-move-tasks
コマンドで DLQ 再処理の状況を確認したところ,大きく CANCELLING
と CANCELLED
の2種類を確認できた.最終的にメッセージが11件移動されてからキャンセルされていた.
$ aws sqs list-message-move-tasks --source-arn ${MAIN_QUEUE_DLQ_ARN} { "Results": [ { "Status": "CANCELLING", "SourceArn": "arn:aws:sqs:ap-northeast-1:123456789012:main-queue-dlq", "MaxNumberOfMessagesPerSecond": 1, "ApproximateNumberOfMessagesMoved": 5, "ApproximateNumberOfMessagesToMove": 30, "StartedTimestamp": 1686875997267 } ] } $ aws sqs list-message-move-tasks --source-arn ${MAIN_QUEUE_DLQ_ARN} { "Results": [ { "Status": "CANCELLED", "SourceArn": "arn:aws:sqs:ap-northeast-1:123456789012:main-queue-dlq", "MaxNumberOfMessagesPerSecond": 1, "ApproximateNumberOfMessagesMoved": 11, "ApproximateNumberOfMessagesToMove": 30, "StartedTimestamp": 1686875997267 } ] }
期待通りに main-queue
と main-queue-dlq
それぞれのメッセージ件数も中途半端な状態で止まっていた👌
$ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "11" } } $ aws sqs get-queue-attributes --queue-url ${MAIN_QUEUE_DLQ} --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "19" } }
参考
今回は AWS CLI v2.11.27 を使ったけど,今回の API は v2.11.26 でサポートされている🆕
boto3 だと v1.26.148 でサポートされている🆕
\( 'ω')/ 試す前にアップデートをお忘れなく〜