Help us understand the problem. What is going on with this article?

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がエラーのレスポンス返して来たときに再実行しているあたりがどうなるのか検証必要ですね…
おそらく明示的にエラーだよと返してあげれば良いのでしょうが…

ではまた!

is_ryo
(IoTチョットワカル)フロントエンドエンジニア。 Vue.js / AWS / GraphQL / Serverless
https://is-ryo.com
acall
ACALLは、「Life in Work and Work in Life for Happiness」をVISIONとして、どこでも安心・安全・快適なワークスタイルを実現するワークスペース管理プラットフォーム「WorkstyleOS」を開発・提供しています。オフィスワークとリモートワークのベストミックスを通じて、人々の「くらし」と「はたらく」を自由にデザインできる世界を目指します。
https://www.workstyleos.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away