Posted at

AWS LambdaがNode.js8.10をサポートしたのでasync/awaitを試してみた

More than 1 year has passed since last update.


はじめに

本日(2018/04/03)、AWSからこんなアナウンスが来ました。

やっとLambdaがNode.js8系に対応してくれましたので、早速 async/await を試してみました。


デモっていきましょう

Lambdaの作成方法は割愛します。コンソール画面から作成していただくとか、ServerlessFrameworkから作成していただくとかしてください。

ランタイムは Node.js 8.10 を指定してください。

今回のデモではDynamoDBにscanとqueryを実行するので、その権限は持っているようにIAMRoleを設定してください。


デモで使っているDynamoDBはこんな感じ


  • TableName: demo-table

  • HashKey: id

id
name

1
tanaka

2
sato

3
mori


ソースコードはこんな感じ

ちなみにランタイム Node.js6.10 のときはこんな感じで書いてました。


index.js

const AWS = require("aws-sdk");

const DynamoDB = new AWS.DynamoDB.DocumentClient({
region: "ap-northeast-1"
});
const co = require("co");

exports.handler = (event, context, callback) => {
co(function *(){
// scanの実行
const scanItems= yield DynamoDB.scan({TableName: "demo-table"}).promise();
// queryの実行
const queryItems = yield DynamoDB.query({
TableName: "demo-table",
KeyConditionExpression: "#ID = :ID",
ExpressionAttributeNames: {"#ID": "id"},
ExpressionAttributeValues: {":ID": "1"}
}).promise();
return {
scan: scanItems,
query: queryItems
};
}).then(data => {
return callback(data);
}).catch(err => {
return callback(err);
});
};


上記では co モジュールを使っていますが、この場合はローカルでcoをnpm installしてZipで固めるなりしてアップロードしなければいけません。

それか

promise().then(data_1 => {

promise().then(data_2 => {
...
})
})

というような形で書くかですね…きったねぇ………

ランタイム Node.js8.10 で書くとこうなります。


index.js

const AWS = require("aws-sdk");

const DynamoDB = new AWS.DynamoDB.DocumentClient({
region: "ap-northeast-1"
});

exports.handler = async (event) => {
try {
// scanの実行
const scanItems= await DynamoDB.scan({TableName: "demo-table"}).promise();
// queryの実行
const queryItems = await DynamoDB.query({
TableName: "demo-table",
KeyConditionExpression: "#ID = :ID",
ExpressionAttributeNames: {"#ID": "id"},
ExpressionAttributeValues: {":ID": "1"}
}).promise();
// scanとqueryの結果をreturnする
return {
scan: scanItems,
query: queryItems
};
} catch (err) {
// エラー発生時はエラー文をreturnする
console.error(`[Error]: ${JSON.stringify(err)}`);
return err;
}
};



結果

{

"scan": {
"Items": [
{
"id": "2",
"name": "sato"
},
{
"id": "1",
"name": "tanaka"
},
{
"id": "3",
"name": "mori"
}
],
"Count": 3,
"ScannedCount": 3
},
"query": {
"Items": [
{
"id": "1",
"name": "tanaka"
}
],
"Count": 1,
"ScannedCount": 1
}
}


さいごに

今まで非同期処理を実行するときは毎回Promiseで囲ったり、Promiseを返すようにしたり、俗に言うPromise地獄にハマることがよくあったのですが、async/awaitを使うことによって治安がよくなりそうです。

あとは現状動き続けているLambda達をメンテしていくという苦行が待っていますが、治安を守るために必要なことですので、少しづつ対応をしていこうと思います……


余談

余談ですが、上記のソースコードでわざとエラーを起こしたときに、Lambda自体は成功となっていたので、KinesisDataStreamsでLambdaがエラーのレスポンス返して来たときに再実行しているあたりがどうなるのか検証必要ですね…

おそらく明示的にエラーだよと返してあげれば良いのでしょうが…

ではまた!