ServerlessFrameworkでSQSをデプロイする2つの書き方

# ServerlessFrameworkでSQSをデプロイする2つの書き方
ServerlessFrameworkを使用してLambdaやその周辺サービスを管理・デプロイするケースはよくあると思います。
LambdaのトリガーとしてSQSを設定したときに2つの実装の仕方があったので備忘録を兼ねて書き留めていきます

2つの実装についてはこちらになります
- serverless-lift プラグインを使用する
- resources セクションを使用する


## serverless-lift プラグインを使用する
こちらはServerlessのイベントとしてsqsを指定する箇所のドキュメントになります
このページの一番下で`serverless-lift`について紹介してあります

https://www.serverless.com/framework/docs/providers/aws/events/sqs

このプラグインを追加すると`constructs`セクションを記述できるようになり
functionsセクションと似たような書き方ができる他に
- デッドレターキューの作成
- 失敗した場合のリトライ回数は設定なしなら3回
- リトライ超えた際のデッドレターキューの保存期間自動設定

などデフォルトでも本番に適した設定が自動的に適用されます :smile: 

導入方法は簡単で
1. プラグインのインストール
1. プラグインとconstructsセクションをymlに記述

↓プラグインのインストール
```sh
$ serverless plugin install -n serverless-lift
```

↓プラグインとconstructsセクションをymlに記述
```yml
plugins:
    - serverless-lift
constructs:
    my-queue:
        type: queue
        worker:
            handler: handler.hello
```

functions配下にeventとしてsqsやsnsなどのサービスを指定する普段のserverlessとの書き方と違うところとして
constructs配下にqueueを作成してその配下にworkerとしてfunctionを指定する書き方になっています


## resourcesセクションを使用する
ymlファイルの中にあるresourcesセクションを使用することでLambdaが使用する各種AWSリソースを作成できます

https://www.serverless.com/framework/docs/providers/aws/guide/resources

先程と違い
「デッドレターキューの自動作成」「リトライ最大実行回数」などについては自身で設定する必要があり
functionsとは少し書き方が異なってきます
実際に先程の`serverless-lift`で書いた内容を**resources**に書き直したymlはこちらです



```yml:serverless.yml
functions:
  hello:
    handler: handler.hello
    events:
      - sqs:
          arn:
            Fn::GetAtt:
              - MyQueue
              - Arn
resources:
  Resources:
    MyQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: my-queue
```
以前よりも書く量も増えたし、さっきになかった記述などがいくつか出てきましたね
「serverless-lift使ってやるほうでええんちゃう？」という意見もあると思います
resourcesセクションの良さとしては「**CloudFormationのドキュメントに載っている内容が定義できる**」ことや「Lambdaに**関係のないリソースも記載できる**ところにあります」

まず**CloudFormationのドキュメントに載っている内容が定義できる**とはどういうことなのか


### CloudFormationのドキュメントに載っている内容が定義できる
こちらがCloudFormationでSQSのQueueをyamlで定義する構文です

```yaml
Type: AWS::SQS::Queue
Properties: 
  ContentBasedDeduplication: Boolean
  DeduplicationScope: String
  DelaySeconds: Integer
  FifoQueue: Boolean
  FifoThroughputLimit: String
  KmsDataKeyReusePeriodSeconds: Integer
  KmsMasterKeyId: String
  MaximumMessageSize: Integer
  MessageRetentionPeriod: Integer
  QueueName: String
  ReceiveMessageWaitTimeSeconds: Integer
  RedriveAllowPolicy: Json
  RedrivePolicy: Json
  SqsManagedSseEnabled: Boolean
  Tags: 
    - Tag
  VisibilityTimeout: Integer
```

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html

このドキュメントさえ見れば自分の任意のオプションを有効にできます
例えばキューの名前を「anpan」、FIFOオプションを「有効化」にする場合は下記のようになります


```diff_yaml:serverless.yml
resources:
  Resources:
    MyQueue:
      Type: AWS::SQS::Queue
      Properties:
-        QueueName: my-queue
+        QueueName: anpan
+        FifoQueue: true
```

CloudFormationに記載がある定義がそのまま使えるということで
serverlessがv3からv4に上がったとき
serverless-liftがv4に未対応の場合で上げられないというリスクは取らなくて済むことや
一次ドキュメントがあるので信頼性が高いと思います

続いて「Lambdaに関係のないリソースも記載できる」という内容について説明します

### Lambdaに関係のないリソースも記載できる
今回はSQS→Lambdaとしましたが、このSQSの前に別のリソースがあるときも簡単にかけるということです
↓のymlでは作成したSQSへイベントを渡すSNSを定義した例です

```diff_yaml:serverless.yml
resources:
  Resources:
    MyQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: my-queue
        DelaySeconds: 60
+   MyTopic:
+     Type: AWS::SNS::Topic
+     Properties:
+       TopicName: my-topic
+       Subscription:
+         - Endpoint:
+             Fn::GetAtt:
+               - MyQueue
+               - Arn
+           Protocol: sqs
functions:
  hello:
    handler: handler.hello
    architecture: arm64
    memorySize: 128
    timeout: 10
    events:
      - sqs:
          arn:
            Fn::GetAtt:
              - MyQueue
              - Arn
```

このようにLambdaと直接関わらないAWSのリソースもまとめて記載できます

:::note warn
上記のコードそのままだとSQSのアクセスポリシーがないため
SNS→SQSへ正しく送信されないのでご注意を
:::


## 最後に
軽く使って見て「serverless-lift」と「resources」どちらにも良い点があるので脳死で「こっち使おうぜ」というのは無いように感じました。
ただ、自分がどんなケースでどちらを選ぶかだと
- サクッと作るなら**serverless-lift**
- 長い付き合いになりそうなら**resources**

といった感じで選ぶと思います。
また、resourcesとserverless-liftが片方だけしか使えないわけではなく、同時に使用はできますので
ユースケースに合わせて選択していくと良さそうですね