Amazon SQSのデッドレターキューの挙動を確認

# はじめに
年明けから重いInputは気分的に乗らなかったので、なんとなく気になっていたSQSを軽ーく動作確認してみました。
ドキュメントを読んで初めてデッドレターキューなる存在を知ったので、挙動を確認して、自分用にまとめます。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html

## 結論

- 可視性タイムアウト期間を過ぎたメッセージはエラー扱いとなる。
- customerはPrimaryキュー側の「最大受信数」まで同じメッセージを受信することができる。
- 例えば最大受信数が1の場合、customerは1度だけ同じメッセージを受信することができる。
- 受信数が最大受信数をむかえ、かつエラーとなったメッセージは、**次のメッセージがcustomerに受信されたタイミングで**デッドレターキューに送信される。

#### ①正常系
![cap_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/2eaf411a-1463-8684-ab06-9dceec676d68.png)

可視性タイムアウト期間内にメッセージを削除するパターンです。
次回リクエストでは次のメッセージが受信できます。
デッドレターキューへのメッセージの送信はありません。

#### ②異常系

![cap_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/9c6e1d4e-544e-ad5d-d24f-da9e2800cd17.png)

可視性タイムアウト期間外にメッセージを削除するパターンです。
削除は失敗します。
キューの最大受信回数設定によって、次回リクエストで受信するメッセージが変化します。

エラーが発生したメッセージが最大受信回数を迎えてない場合、同じメッセージが受信されます。
デッドレターキューへのメッセージの送信はありません。

エラーが発生したメッセージが最大受信回数を迎えていた場合、次のメッセージが受信されます。
デッドレターキューへは最大受信回数を迎えたメッセージが送信されます。

#### ③異常系

削除コマンドを送信しなくても、可視性タイムアウト期間が過ぎればメッセージはエラー扱いとなります。
エラー後の挙動は②の異常系と同じです。

![cap_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/610398f0-4a56-a621-a994-d780f94cc8ab.png)

## 動作確認

#### キューの設定
Primaryと勝手に読んでいる、デッドレターを送信する側のキューの設定です。
デッドレターキューのArnを指定します。

![cap2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/60397f74-7fdc-1f40-66c1-da7f56cdb438.png)

![cap1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/6ed64ee1-9955-6111-50ae-6d0a920e3eed.png)

デッドレターを受信する側のキューの設定です。

![cap4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/ccd3e550-023c-1022-c2a1-b257362f948e.png)

![cap3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/ec4600c9-008f-01f9-92f5-2d6ed4e22bd2.png)

#### テスト用aws cliコマンド

```send-message.sh
aws sqs send-message --queue-url ${PRIMARY_QUEUE_ENDPOINT} \
 --message-body "{\"type\": \"test\", \"index\": \"001\", \"text\": \"aaa\"}" \
 --message-deduplication-id $(openssl rand -base64 20 | tr -d '\n') \
 --message-group-id test_group \
 --output json
```

```receive-message.sh
aws sqs receive-message --queue-url ${PRIMARY_QUEUE_ENDPOINT} \
 --attribute-names all \
 --output json
```

```delete-message.sh
aws sqs delete-message --queue-url ${PRIMARY_QUEUE_ENDPOINT} \
--receipt-handle ${RECEIPT_HANDLE} \
--output json
```


簡単にですが3つのパターンで動作を確認してみました。
#### ①正常系

1. デッドキューメッセージの取得
→receive-messageコマンドでデッドキューメッセージを取得します。
→何も受信しません。

2. Primaryキューメッセージの作成
→send-messageコマンドでPrimaryキューメッセージを取得します。
→作成されたmessageIdが取得できます。

3. Primaryキューメッセージの作成
→send-messageコマンドでPrimaryキューメッセージを送信します。
→作成されたmessageIdが取得できます。

4. Primaryキューメッセージの取得
→receive-messageコマンドでPrimaryキューメッセージを取得します。
→2. で作成したmessageの内容とReceiptHandleが取得できます。

5. Primaryキューメッセージの削除
→delete-messageコマンドでPrimaryキューメッセージを削除します。
→messageの内容とReceiptHandleが取得できます。
→エラーがなければ、何も返却されません。

6. デッドキューメッセージの確認
→receive-messageコマンドでデッドキューメッセージを取得します。
→何も受信しません。

7. Primaryキューメッセージの取得
→receive-messageコマンドでPrimaryキューメッセージを取得します。
→3. で作成したmessageの内容とReceiptHandleが取得できます。

#### ②異常系

1. デッドキューメッセージの取得
→receive-messageコマンドでデッドキューメッセージを取得します。
→何も受信しません。

2. Primaryキューメッセージの作成
→send-messageコマンドでPrimaryキューメッセージを送信します。
→作成されたmessageIdが取得できます。

3. Primaryキューメッセージの作成
→send-messageコマンドでPrimaryキューメッセージを送信します。
→作成されたmessageIdが取得できます。

4. Primaryキューメッセージの取得
→receive-messageコマンドでPrimaryキューメッセージを取得します。
→2. で作成したmessageの内容とReceiptHandleが取得できます。

5. 可視性タイムアウト期間待機
→Primaryキューメッセージで設定した可視性タイムアウト期間待機します。

6. デッドキューメッセージの確認
→receive-messageコマンドでデッドキューメッセージを取得します。
→1つ目のメッセージはエラーになっていますが、まだデッドレターキューからは何も受信しません。

7. Primaryキューメッセージの削除
→delete-messageコマンドでPrimaryキューメッセージを削除します。
→期限超過のエラーが返却されます。

8. デッドキューメッセージの確認
→receive-messageコマンドでデッドキューメッセージを取得します。
→1つ目のメッセージはエラーになっていますが、まだデッドレターキューからは何も受信しません。

9. Primaryキューメッセージの取得
→receive-messageコマンドでPrimaryキューメッセージを取得します。
→3. で作成したmessageの内容とReceiptHandleが取得できます。

10. デッドキューメッセージの確認
→receive-messageコマンドでデッドキューメッセージを取得します。
→2. で作成したmessageの内容とIdが取得できます。

#### ③異常系
～②と同じなので省略～

#### デッドレターキューの設定がない場合の挙動
※デッドレターキュー設定のない別キューを用意
1. キューメッセージの作成
→send-messageコマンドでキューメッセージを送信します。
→作成されたmessageIdが取得できます。

2. キューメッセージの取得
→receive-messageコマンドでキューメッセージを取得します。
→1. で作成したmessageの内容とReceiptHandleが取得できます。

3. 可視性タイムアウト期間待機
→キューで設定した可視性タイムアウト期間待機します。

4. Primaryキューメッセージの取得
→receive-messageコマンドでキューメッセージを取得します。
→1. で作成したmessageの内容とReceiptHandleが取得できます。

デッドレターキューへの転送がないので、スキップされることなく、滞留してくれています。


# 終わりに
SQSのデッドレターキューを触ってみました。

こんな機能があることを知らなかったので最初はドキュメントを読むのが怖かったですが、使ってみるとなるほど便利だと思いました。

実は最初はSQS受信→lambdaの自動発火を試そうとしていたので、次はそっちを試してoutputできたらなと思います。