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は以下のようにプロジェクトの後につく名前のようです

自分もまだわかっていないので知っている人がいたら教えて欲しいです!

デプロイ

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

デプロイと同時にロールも作成されるのでIAMのマネジメントコンソール画面でSQS
とりあえず全てFullAccessで

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のコンソール画面に移動してトリガーの設定をします

SQSコンソール画面からメッセージを送信してみましょう

CloudWatchで出力されているか確認できます

出力されていません(ノ゚ο゚)ノ オオオオォォォォォォ-
どうやらメッセージを取得できていないようです

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


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がいらないことに気付く