DynamoDBのチュートリアルを読み解く【4: Lambda 関数を作成してテストする】

# はじめに

引き続き[DynamoDBのチュートリアル](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.Lambda.Tutorial.html)を実施しました。
今回はLambdaです。

（バックナンバー）
[1.DynamoDB テーブル作成](https://qiita.com/kkino1985/items/f9091c1e1efb35009ce7)
[2.IAMポリシー/ロール作成](https://qiita.com/kkino1985/items/a087bc3077f36b4b1e21)
[3.SNSトピック作成](https://qiita.com/kkino1985/items/f40d950cfd6d464635fa)


# 4.1 Lambda用Javascriptファイル作成

javascriptは専門外なので深入りはしませんが、使われているメソッドをピックアップします。

    'use strict';
    var AWS = require("aws-sdk");
    var sns = new AWS.SNS();
    
    exports.handler = (event, context, callback) => {
    
        event.Records.forEach((record) => {
            console.log('Stream record: ', JSON.stringify(record, null, 2));
            
            if (record.eventName == 'INSERT') {
                var who = JSON.stringify(record.dynamodb.NewImage.Username.S);
                var when = JSON.stringify(record.dynamodb.NewImage.Timestamp.S);
                var what = JSON.stringify(record.dynamodb.NewImage.Message.S);
                var params = {
                    Subject: 'A new bark from ' + who, 
                    Message: 'Woofer user ' + who + ' barked the following at ' + when + ':\n\n ' + what,
                    TopicArn: 'arn:aws:sns:region:accountID:wooferTopic'
                };
                sns.publish(params, function(err, data) {
                    if (err) {
                        console.error("Unable to send message. Error JSON:", JSON.stringify(err, null, 2));
                    } else {
                        console.log("Results from sending message: ", JSON.stringify(data, null, 2));
                    }
                });
            }
        });
        callback(null, `Successfully processed ${event.Records.length} records.`);
    }; 

## console.log()

Webコンソールにメッセージを出力する。
Webコンソールとはウェブページやネットワークリクエストなどについて様々な情報が出力される画面で、各種ブラウザには備わっているもの。

https://developer.mozilla.org/ja/docs/Web/API/Console/log

※Google ChromeでWebコンソールを開く手順

https://developers.google.com/web/tools/chrome-devtools?hl=ja

## JSON.stringify()

入力したオブジェクト等をJSON形式にて出力する。
引数も色々あるようですが、今回の本筋ではないので割愛。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify


# 4.2 jsファイルをアーカイブ（zip）

チュートリアルではzipコマンドの手順となっていますが、Windowsではzipコマンドが（標準では）使えないので、今回はPowerShellからzipしました。

    powershell Compress-Archive -Path publishNewBark.js -DestinationPath publishNewBark.zip

今回は使いませんでしたが、`-Force`でzipファイルが存在する場合に上書き、`-Update`オプションで既存のzipファイルに指定したファイルを追加する、という動作になります。
（デフォルトでは上書きできないので注意）


# 4.3 Lambda関数作成

4.1、4.2で作成したjsファイル（zip）を使ってLambda関数を作成します。

その前に、コマンドの引数で以前作成したWooferLambdaRoleのARNが必要になるので、情報取得します。

    aws iam get-role --role-name WooferLambdaRole

実行すると色々出力されますので、`"ARN"`の部分を抜き出します。

（出力例）

    ....
    "RoleId": "AROAXZP7LF63B7AGDS33T",
    "Arn": "arn:aws:iam::xxxxxxxxxxxxx:role/service-role/WooferLambdaRole",
    "CreateDate": "2020-01-28T17:06:32Z",
    ....

情報が取れたら、Lambda関数を作成します。

    aws lambda create-function \
        --region us-east-1 \
        --function-name publishNewBark \
        --zip-file fileb://publishNewBark.zip \
        --role `roleARN` \
        --handler publishNewBark.handler \
        --timeout 5 \
        --runtime nodejs10.x


## --region

公式のコマンドリファレンスには--regionオプションについて記載がありませんでしたが、マネジメントコンソールで確認すると確かにus-east-1（バージニア北部）リージョンで作成されていました。

![lambda画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319027/c4d1a194-8d06-8963-5166-07f956003a40.png)

感動した！（KIZM元首相）と思いましたが、自分の環境は東京リージョンで、バージニアに作られるとこの後の手順に支障が出るので作成し直しました。
（地味なハマりポイント）



## --function-name

- 書式 : --function-name `(value)`

関数の名前。
（名前の書き方には色々あるようですが、ここでは割愛）

## --zip-file

- 書式 : --zip-file fileb://`(filepath)`

登録するコード（zip）のパス。

### 2020/2/2追記
--regionはawsコマンド自体のオプションのため、個別のリファレンスには載ってないというだけのようです。
（--outputや--filtersと同じ扱い）

## --role

- 書式 : --role `(arn)`

関数の実行ロールのリソースネーム（ARN）を指定。


## --handler

- 書式 : --handler `(value)`

Lambdaが関数を実行するために呼び出すコード内のメソッドの名前。


## --timeout

- 書式 : --timeout `(value)`

Lambda関数の実行許容時間。デフォルトは3秒で、最大値は900秒。

短いようですが、Lambda関数は常駐させず、一回ポッキリで終わる処理で使うのがベストプラクティスであり、タイムアウトを迎えてしまう場合はそもそもの設計を見直した方が良い、と聞いたことがあります。


## --runtime

- 書式 : --runtime `(value)`

関数のランタイム（実行環境）。
JavaやPythonなど、色々指定可能。
（10.xは最初最新バージョンを手入力するのかと思いましたが、これはこういうものらしいです）


# 4.4 Lambda関数のテスト

チュートリアルに従ってpayload.jsonを作成し、テスト実施。

    aws lambda invoke  --function-name publishNewBark --payload file://payload.json output.txt

※invoke：呼び出す

実行して"StatusCode"に200が返ってくれば成功です。

    {
        "StatusCode": 200,
        "ExecutedVersion": "$LATEST"
    }

output.txtにも成功メッセージが出力されました。
（ついでに登録したアドレス宛にメールが送られました）

    "Successfully processed 1 records."

# 参考URL

https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html