SQSをイベントソースしてlambdaを動かす

#はじめに
[AWS lambdaでSQSのサポート](https://forums.aws.amazon.com/ann.jspa?annID=5875)が発表されていたのでServerlessFrameworkとpipenvを使いデプロイを行っていこうと思います
はまったところもあるので記述

# 環境
* OS: macOS HighSierra
* Python: 3.6.5
* pipenv: 2018.7.1
* serverless: 1.29.2

#諸々インストール
* serverless

```
npm install --save serverless
```
* serverless-python-requirements(モジュールを一緒にデプロイするために必要)

```
sls plugin install -n serverless-python-requirements
```
* pipenv

```
pip install pipenv
```

# プロジェクトを作成
* 以下のコマンドでプロジェクトを作成

```
$ sls create -t aws-python3 -n sqs -p sqs
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/shimizukousuke/Desktop/sqs"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.29.2
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"
```
`-n`はプロジェクトの名前、`-p`はサービスを作成するpath

```
$ tree sqs                                                                                                                                                                      [~/Desktop]
sqs
├── handler.py
└── serverless.yml
```
こんな感じで作ってくれます

#pipenv
* 仮想環境を構築

```
pipenv install
```


* モジュールをインストール

```
pipenv install boto3
```
SQS触るために`boto3`　 (後に必要ないと気付く)


# serverless.ymlの編集
* 以下の項目を記述

```yaml

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    usePipenv: true 
```
serverless-python-requirementsはrequirements.txtをもとにパッケージをビルドしてくれます
(今回はpipenvで作ったPipfileですが)
`usePipenv: true`と記述することによってserverless-python-requirementsに対してrequirements.txtではなくPipfileを見に行ってくれます

自動的に生成されたファイルなのでコメントが煩わしかったので私はコメントを全て無くしました

* functionsを変更

```yaml
functions:
  hello: # ※1
    handler: handler.hello # handler.pyのhello関数
```
最初はこのようになっているのでhandlerを編集しましょう
※1 どうやらこの`hello`は以下のようにプロジェクトの後につく名前のようです
<img width="319" alt="スクリーンショット 2018-08-07 15.06.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/6cdf8bab-67f1-bc46-6ef5-437731dc51c3.png">
自分もまだわかっていないので知っている人がいたら教えて欲しいです！

# デプロイ
* 以下のコマンドでデプロイ　色々よしなにやってくれます

```
sls deploy -v 
```

* ロールの設定

デプロイと同時にロールも作成されるのでIAMのマネジメントコンソール画面でSQS
とりあえず全てFullAccessで
<img width="323" alt="スクリーンショット 2018-08-07 16.10.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/b62fa054-0541-4e64-e51d-dc2e635e967e.png">


# SQSからメッセージを取得
とりあえずSQSからメッセージを取得してprintしてみます

```python
import boto3
 
logger = logging.getLogger()
logger.setLevel(logging.INFO)

name = 'XXXXXXXXXXX' #  キューの名前を指定
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName=name)

def app_push_tag_from_queue(event, context):
    logger.info(json.dumps(event))
    msg_list = queue.receive_messages(MaxNumberOfMessages=10) #  メッセージを取得
    for message in msg_list:
        print(message.body)
        message.delete()
```
デプロイしてAWS lambdaで確認

AWS lambdaのコンソール画面に移動してトリガーの設定をします
<img width="1337" alt="スクリーンショット 2018-08-07 16.19.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/f2b0f492-fb00-cb6b-ba3c-1bf8a6808989.png">

<img width="1054" alt="スクリーンショット 2018-08-07 15.23.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/69d1d486-75e8-fa59-a751-250f283555d1.png">

SQSコンソール画面からメッセージを送信してみましょう
<img width="609" alt="スクリーンショット 2018-08-07 15.24.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/577ac3cb-6b94-8ce7-8efe-abc977e7785d.png">

CloudWatchで出力されているか確認できます
<img width="1350" alt="スクリーンショット 2018-08-07 15.31.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/d40753ab-62d3-7085-b8f2-68c4a2ebf12c.png">
出力されていません(ﾉﾟοﾟ)ﾉ ｵｵｵｵｫｫｫｫｫｫ-
どうやらメッセージを取得できていないようです

# メッセージを取得できない原因と解決法
<img width="851" alt="スクリーンショット 2018-08-07 15.48.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/0044f125-fd3c-a021-ad72-197e9d3a44ac.png">
boto3でSQSのメッセージを取得する際、利用可能なメッセージを取得しに行く
しかし、SQSをlambdaのトリガーに設定するとトリガーされた段階でそのメッセージは処理中に移動する
その後、boto3がSQSの利用可能なメッセージを取得しにいくのでメッセージは取得できない

メッセージはeventのRecordsの中に入っているのでそこから取得する(そういえば上の画像にRecordsあった)

```python
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def app_push_tag_from_queue(event, context):
    for record in event['Records']:
        logger.info(record['body'])
```
これでOK
ちなみに[公式のドキュメント](https://aws.amazon.com/jp/blogs/news/aws-lambda-adds-amazon-simple-queue-service-to-supported-event-sources/)に書いてありました（´-｀;）トホホ 
そして`boto3`がいらないことに気付く