Lambda(SAM)からAWS SQS(LocalStack) へメッセージ送信/受信を行う方法 メモ

* LocalStack上で動くAWS SQSのキューに対してAWS SAM CLIで動くLambdaからメッセージ送受信を行う方法をメモする。

## 構成

![sam-sqs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/862d727c-e543-8b0d-7c15-193655e62a39.png)


## LocalStack準備

* `docker-compose.yml`

  ```yaml
  version: "3.8"
  networks:
    container-link:
      name: docker.internal
  services:
    localstack:
      container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
      image: localstack/localstack
      ports:
        - "127.0.0.1:53:53"                # only required for Pro
        - "127.0.0.1:53:53/udp"            # only required for Pro
        - "127.0.0.1:443:443"              # only required for Pro
        - "127.0.0.1:4510-4530:4510-4530"  # only required for Pro
        - "127.0.0.1:4566:4566"
        - "127.0.0.1:4571:4571"
      environment:
        - SERVICES=${SERVICES- }
        - DEBUG=${DEBUG- }
        - DATA_DIR=${DATA_DIR- }
        - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
        - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- }  # only required for Pro
        - HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
        - DOCKER_HOST=unix:///var/run/docker.sock
      volumes:
        - "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
        - "/var/run/docker.sock:/var/run/docker.sock"
      networks:
        - container-link
  ```

* 起動

  ```shell
  docker-compose up
  ```

  



## SQS準備

### キュー作成

```shell
aws sqs create-queue --queue-name test-queue --endpoint-url http://localhost:4566 --profile localstack 
{
    "QueueUrl": "http://localhost:4566/000000000000/test-queue"
}
```



### キューの確認

```shell
aws sqs list-queues --endpoint-url http://localhost:4566 --profile localstack 
{
    "QueueUrls": [
        "http://localhost:4566/000000000000/test-queue"
    ]
}
```



## Lambda準備

### Lambda

* ひな形作成

  ```shell
  sam init
  ```

  ※ランタイムはPython3.8を選択。

* `template.yml`

  * Hello World Exampleを利用する。

  * POST(メッセージ送信)/GET(メッセージ受信)用に以下修正

    ```yaml
    Events:
            SendMessage:
              Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
              Properties:
                Path: /message
                Method: post
            ReceiveMessage:
              Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
              Properties:
                Path: /message
                Method: get
    ```

    

* `requrements.txt`

  ```
  requests
  boto3
  ```

  ※SQSアクセス用にboto3追加

  

* Lambda処理(`app.py`)修正

  ```python
  import json
  from boto3.session import Session
  from datetime import datetime
  
  # SQS 接続設定
  session = Session(
      aws_access_key_id='dummy',
      aws_secret_access_key='dummy',
      region_name='ap-northeast-1'
  )
  client = session.client(
      service_name='sqs', 
      endpoint_url='http://localstack:4566'
  )
  
  
  def lambda_handler(event, context):
      # キューURL
      queue_url="http://localstack:4566/000000000000/test-queue"
      if event["httpMethod"] == "POST":
          # メッセージ送信
          response = client.send_message(QueueUrl=queue_url, MessageBody=json.dumps(event["body"]))
          res = {"MD5OfMessageBody":response["MD5OfMessageBody"],"MessageId":response["MessageId"]}
          return {
              "statusCode": 200,
              "body": json.dumps(res),
          }
      if event["httpMethod"] == "GET":
          # メッセージ受信
          response = client.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=1, VisibilityTimeout=60)
          # メッセージ削除
          for message in response["Messages"]:
              client.delete_message(QueueUrl=queue_url, ReceiptHandle=message["ReceiptHandle"])
  
          return {
              "statusCode": 200,
              "body": json.dumps(response["Messages"][0]),
          }
  
  ```



## 動作確認

* ビルド

  ```
  sam build
  ```

* 実行

  ```
  sam local start-api --docker-network docker.internal
  ```

* メッセージ送信

  * リクエスト

    ```http
    POST /message HTTP/1.1
    Host: localhost:3000
    Content-Type: application/json
    Content-Length: 34
    
    {
        "message":"test message1"
    }
    ```

  * レスポンス

    ```json
    {
        "MD5OfMessageBody": "65b7b348e7f42918ad0d487de1a20c47", 
        "MessageId": "2cafdcd9-2620-14b4-645a-da15dbddf8b5"
    }
    ```

    

* メッセージ受信

  * リクエスト

    ```http
    GET /message HTTP/1.1
    Host: localhost:3000
    Content-Type: application/json
    ```

  * レスポンス

    ```json
    {
        "MessageId": "2cafdcd9-2620-14b4-645a-da15dbddf8b5", 
        "ReceiptHandle": "imvqeantfgqrgtkzhwowwzywsxmtdrakkhjdqkwyybxlevsltiefnfjrmoksniovizimonlkixhdixufzqlmejbmtwcxvwuaintwwojbompbfqjhsmokjtojxdlnxquvqslbrevmrinvzxeymkrcpstcmzrtfzhlclwpmkcuokfqjdahkiqhlxcli", 
        "MD5OfBody": "65b7b348e7f42918ad0d487de1a20c47", 
        "Body": "\"{\\n    \\\"message\\\":\\\"test message1\\\"\\n}\""
    }
    ```

    

## 参考情報

* [AWS SQSのメッセージをPythonで送受信する](https://ohke.hateblo.jp/entry/2019/10/19/230000)