【AWS】SQSの使い方を知る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/ede7160f-3dbb-ab5d-a6d6-33cd03a86aca.png)

# はじめに
どーも、のぶこふです。
この記事は[GFAMアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/gfam)の18日目の記事です。

なんか好きなんですよね、SQS。
試験では、SNSとか、SESとか、MQとかと一緒に出題されることが多いですね。
良いですよねー、SQS。
まぁ、全く使ったこともないので、完全な片思い状態ですがっ！

ということで、今回はSQSとの馴れ初め回です。

概要とかを書いていると、全然「触ってみた」に辿り着けないので、やってみるファーストを意識していこうと思います。

# 何がしたいのか？
* Amazon SQS の使い方を知る。使ってみる。

# 今回のサービス一覧

|Service名とか|概要|
|--|--|
|SQS[^sqs]|フルマネージド型のメッセージキューイングサービス|

## AWSが提供するメッセージサービス
* Amazon Simple Notification Service（SNS）
* Amazon Simple Queue Service（SQS）
* Amazon MQ

大分類で３つ。
ストリーミングなら、Kinesisの名前が挙がりますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/12441399-7cac-200a-2a77-f68dc0d59bfa.png)

## SQS
参考：[Blackbelt](https://www.slideshare.net/AmazonWebServicesJapan/20190717-aws-black-belt-online-seminar-amazon-simple-queue-service)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/9f53f232-5443-4ebc-7860-477d7cbebde7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/9637f07e-9bef-6347-14dc-ddf72c75a707.png)


# やってみる
### キューの作成
なにはともあれ、マネジメントコンソールからアクセスして、「キューを作成」します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/401a4ce2-c598-d00b-bccb-2e87b303c138.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/172732c7-8724-837c-d17e-f9372fcd786f.png)

* タイプや名前等を設定します。
    * 可視性タイムアウトやショート・ロングポーリング（メッセージ受信待機時間）などの設定もここで行います
    * 暗号化やDLQ（デッドレターキュー）と言った設定もここで行います

### メッセージ登録スクリプトを作成する
* CloudShellからスクリプトを作成してみます
    * 参考「[クラスメソッド様：AWS再入門ブログリレー Amazon SQS編](https://dev.classmethod.jp/articles/re-introduction-2020-amazon-sqs/)」
    * AWS CloudShell なら、SDKも入っているので、いろいろと楽です。

```js:sendMessage.js
const AWS = require("aws-sdk")
// 利用するリージョンを指定する
const SQS = new AWS.SQS({ region: "ap-northeast-1" })

// アカウントIDとキューの名前は各人の値を設定してください
const QueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/123456789012/my_queue"

async function sendMessage(message) {
  try {
    const MessageBody = JSON.stringify({ message })
    const result = await SQS.sendMessage({ MessageBody, QueueUrl }).promise()
    console.log(result)
  } catch (e) {
    console.error(e)
  }
}

sendMessage("こんにちは")
```

### メッセージ登録スクリプトを実行する
先程作成したスクリプトを実行します。
CloudShellからなら、Nodeが入っているので楽です。

```bash
$ node sendMessage.sh
{
  ResponseMetadata: { RequestId: 'af4da524-bd5b-55c0-ba7f-ff12a66fe0d1' },
  MD5OfMessageBody: '04366f504cabfb9b64545bd8f0a6012b',
  MessageId: '65f6c3eb-8076-4e9a-adbb-22b4b0bd6f96'
}
```

「利用可能なメッセージ」が増えていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/d5498cb4-ee18-4363-3ec7-0080f1ee2c0a.png)

お試しでもう一度実行しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/6f950ec2-8dac-6641-509d-ebba197b674b.png)

増えました。

### メッセージ取得スクリプトを作成する
登録が終わったので、メッセージを取得するスクリプトを作成します。
CloudShellなら、SDKga・・・

```js:processingMessage.js
const AWS = require("aws-sdk")
const SQS = new AWS.SQS({ region: "ap-northeast-1" })

const QueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/123456789012/my_queue"

async function processingMessage() {
  try {
    const params = {
      QueueUrl,
      MaxNumberOfMessages: 10, // 最大取得メッセージ
      WaitTimeSeconds: 20 // ロングポーリング
    }
    const messages = await SQS.receiveMessage(params).promise() // メッセージを取得
    for (message of messages.Messages) {
      const body = JSON.parse(message.Body)
      console.log(message)
      console.log(body.message) //メッセージの実態
      //重い処理
      await new Promise((resolve, reject) => {
        setTimeout(resolve, 1000)
      })
      const params =  {
        QueueUrl,
        ReceiptHandle: message.ReceiptHandle
      }
      // キューの削除箇所を、あえてコメントアウト
      // const deleteResult = await SQS.deleteMessage(params).promise()
      // console.log(deleteResult)
    }

  } catch (e) {
    console.error(e)
  }
}

processingMessage()
```

キューを削除する処理の箇所を、あえてコメントアウトしてみました。
どのように動くのか確認してみます。

### メッセージ取得スクリプトを実行する
実行してみると・・・

```bash
$ node processingMessage.js
{
  MessageId: 'e190dd19-a4f0-4af3-b9b3-152ef436bc09',
  ReceiptHandle: 'AQEB5C01TO0OtrOpCBn7ahixSm9Ou3AEPGVlsE31lPIY8AZF/hZZO+ZW80QdloS333cUNQF22tO9PNaIvZg7634XyYeHjhaXKFr7N/PKpZOqt/BGmHXFH2AvlipX/K32TJmUunjy+ab6C4MM/L3nZp/9dqG8lkQp44K7JyvykDVrd6axFOCaTVfJCFEiil5F4OBZkGQ6ASM7jfevmxSONoQzWTzVstzvv56FY3lEW0RCSwMCO5oie3UiokC/UyVTOFvWBvGuOf4hP4jhJ2uhsa5igMpN7V6l7lKwk5CEAYT9UOZ3vH1jLAGD06wi8louybjRreh+sYwfi007HE+H0g0GWsTe8iC/T/EmmtIKN4ZHGCZwnT0qilC4tQ59dJL471FEbIuDKc+tp6kha7jDoVJBIA==',
  MD5OfBody: '04366f504cabfb9b64545bd8f0a6012b',
  Body: '{"message":"こんにちは"}'
}
こんにちは
```

登録していた内容が返ってきました。
マネジメントコンソールを見てみると・・・？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/953ef76e-bcc5-64e8-c720-f09634fe6b6a.png)

変わりないですね。

### 削除処理を入れて、再実行する
先程のスクリプトから、コメントアウトしていた箇所を取り外し、削除処理を戻します。

```diff:processingMessage.js
      const params =  {
        QueueUrl,
        ReceiptHandle: message.ReceiptHandle
      }
-      // const deleteResult = await SQS.deleteMessage(params).promise()
-      // console.log(deleteResult)
+      const deleteResult = await SQS.deleteMessage(params).promise()
+      console.log(deleteResult)
    }
```

実行してみると・・・？

```bash
$ node processingMessage.js
{
  MessageId: '65f6c3eb-8076-4e9a-adbb-22b4b0bd6f96',
  ReceiptHandle: 'AQEBfGADqsygPEpBpuU0HYxYd0/qaYk2E8VbOXjv9YjVM8n+CTmMNGQwPuEsMbD3SZmG1r4k6nXy5tjOp/8gmCn+uYtMMbywgt9rcJonzut/u0LbAK84sIV7UHGBbkLTRM25+iomwL72gN5qJXcFiAXwXrIyX+MJmMcyrXWkvE24Sac0z3viPbcquqxFUKBqK38UbBiRJnguFYq2xrlQXEgulT9t8D2Co8OcjkpQHOvoA5fTq68jq4gh0BUDG1VtHpivn+RUWEm4z9F/ZE9oAlABnKWv74RmAn9//tjsiGFYczBPUsIoPjIL6fnY/e2MbuVXxb1V91n14wR40ttUvYTBOG8KN+zENNl7oPxVXFyA/QOSOp6ETqNcSs5k2EV1TXz8XREXw7x58300z6LbRT12NA==',
  MD5OfBody: '04366f504cabfb9b64545bd8f0a6012b',
  Body: '{"message":"こんにちは"}'
}
こんにちは
{
  ResponseMetadata: { RequestId: '236ddd31-5701-529d-815e-8707488bbf4c' }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/17ee4941-45a3-b8be-7b4e-9be8bdd1d98e.png)

利用可能なメッセージも減っていますね！

### メッセージが無い時に、取得するとどうなるのか？
気になったので、利用可能メッセージが０の状態で叩いてみました。
どうやら、エラーが返ってくるようですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/6443b486-e89c-c557-a6c0-cb38a7159b19.png)




# おわりに
今回は、SQSを使ってみました。
お友達にもなれてませんが、一歩近づくことができました。
使ってみて、「やっぱり、なんか良いな」という思いは深まった気がします。

Lambdaからだと、正常処理の場合はメッセージ削除をしてくれるそうなので、どこで使うかを意識してスクリプトを作成する必要がありそうですね。


今回はここまでです。
ありがとうございました。


[^sqs]: [概要](https://aws.amazon.com/jp/sqs/)