Python3
lambda
sqs
ServerlessFramework
Pipenv

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

はじめに

AWS lambdaでSQSのサポートが発表されていたので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の編集

  • 以下の項目を記述
plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    usePipenv: true 

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

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

  • functionsを変更
functions:
  hello: # ※1
    handler: handler.hello # handler.pyのhello関数

最初はこのようになっているのでhandlerを編集しましょう
※1 どうやらこのhelloは以下のようにプロジェクトの後につく名前のようです
スクリーンショット 2018-08-07 15.06.35.png
自分もまだわかっていないので知っている人がいたら教えて欲しいです!

デプロイ

  • 以下のコマンドでデプロイ 色々よしなにやってくれます
sls deploy -v 
  • ロールの設定

デプロイと同時にロールも作成されるのでIAMのマネジメントコンソール画面でSQS
とりあえず全てFullAccessで
スクリーンショット 2018-08-07 16.10.30.png

SQSからメッセージを取得

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

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のコンソール画面に移動してトリガーの設定をします
スクリーンショット 2018-08-07 16.19.25.png

スクリーンショット 2018-08-07 15.23.09.png

SQSコンソール画面からメッセージを送信してみましょう
スクリーンショット 2018-08-07 15.24.44.png

CloudWatchで出力されているか確認できます
スクリーンショット 2018-08-07 15.31.36.png
出力されていません(ノ゚ο゚)ノ オオオオォォォォォォ-
どうやらメッセージを取得できていないようです

メッセージを取得できない原因と解決法

スクリーンショット 2018-08-07 15.48.10.png
boto3でSQSのメッセージを取得する際、利用可能なメッセージを取得しに行く
しかし、SQSをlambdaのトリガーに設定するとトリガーされた段階でそのメッセージは処理中に移動する
その後、boto3がSQSの利用可能なメッセージを取得しにいくのでメッセージは取得できない

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

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
ちなみに公式のドキュメントに書いてありました(´-`;)トホホ
そしてboto3がいらないことに気付く