Node.js の AWS Lambda 関数ハンドラー
Lambda 関数ハンドラーは、イベントを処理する関数コード内のメソッドです。関数が呼び出されると、Lambda はハンドラーメソッドを実行します。ハンドラーによってレスポンスが終了するか、レスポンスが返ったら、別のイベントを処理できるようになります。
次の例の関数では、イベントオブジェクトの内容をログに記録して、そのログの場所を返します。
- CommonJS module handler
-
exports.handler = async function (event, context) {
console.log("EVENT: \n" + JSON.stringify(event, null, 2));
return context.logStreamName;
};
- ES module handler
-
export const handler = async (event, context) => {
console.log("EVENT: \n" + JSON.stringify(event, null, 2));
return context.logStreamName;
};
関数を設定すると、ハンドラー設定の値はファイル名とエクスポートしたハンドラーメソッドの名前をドットで区切ったものになります。コンソールのデフォルトと、このガイドの例では、index.handler
です。これは、handler
ファイルからエクスポートされた index.js
メソッドを示します。
ランタイムでは、ハンドラーメソッドに引数を渡します。最初の引数は、呼び出し元からの情報を含む event
オブジェクトです。呼び出し元は、Invoke を呼び出してこの情報を JSON 形式の文字列として渡し、ランタイムはそれをオブジェクトに変換します。AWS のサービスで関数を呼び出す場合、そのイベント構造はサービスによって異なります。
2 番目の引数は、コンテキストオブジェクトです。この引数には、呼び出し、関数、および実行環境に関する情報が含まれます。前述の例では、関数は、コンテキストオブジェクトからログストリームの名前を取得し、それを呼び出し元に返します。
コールバック引数を使用することもできます。これは、非同期ではないハンドラーで呼び出してレスポンスを送信できる関数です。コールバックの代わりに async/await を使用することをお勧めします。async/await により、読みやすさ、エラー処理、および効率が向上します。async/await とコールバックの違いの詳細については、「コールバックの使用」を参照してください。
async/await の使用
コードが非同期タスクを実行する場合は、async/await パターンを使用して、ハンドラーが実行を確実に終了するようにします。async/await は、Node.js で非同期コードを記述するための簡潔で読みやすい方法であり、ネストされたコールバックや連鎖する promise を必要としません。async/await を使用すると、非同期かつノンブロッキングでありながら、同期コードのように読み取るコードを記述できます。
async
キーワードは関数を非同期としてマークし、await
キーワードは Promise
が解決されるまで関数の実行を一時停止します。
非同期イベントが完了するまでお待ちください。非同期イベントが完了する前に関数が戻る場合、関数が失敗したり、アプリケーションで予期しない動作が発生したりする可能性があります。これは、forEach
ループに非同期イベントが含まれている場合に発生します。forEach
ループは同期呼び出しを想定しています。詳細については、Mozilla ドキュメントの「Array.prototype.forEach()」を参照してください。
- CommonJS module handler
-
例 – async/await を使用した HTTP リクエスト
const https = require("https");
let url = "https://aws.amazon.com/";
exports.handler = async function (event) {
let statusCode;
await new Promise(function (resolve, reject) {
https.get(url, (res) => {
statusCode = res.statusCode;
resolve(statusCode);
}).on("error", (e) => {
reject(Error(e));
});
});
console.log(statusCode);
return statusCode;
};
- ES module handler
-
例 – async/await を使用した HTTP リクエスト
この例では、nodejs18.x
ランタイムで使用できる fetch
を使用します。
const url = "https://aws.amazon.com/";
export const handler = async(event) => {
try {
// fetch is available with Node.js 18
const res = await fetch(url);
console.info("status", res.status);
return res.status;
}
catch (e) {
console.error(e);
return 500;
}
};
次の例では、async/await を使用して Amazon Simple Storage Service バケットを一覧表示します。
この例を使用する前に、関数の実行ロールに Amazon S3 の読み取り許可があることを確認してください。
- CommonJS module handler
-
例 – async/await を使用した AWS SDK v2
この例では、Node.js 12、14、および 16 ランタイムで使用可能な AWS SDK for JavaScript v2 を使用します。
const AWS = require('aws-sdk')
const s3 = new AWS.S3()
exports.handler = async function(event) {
const buckets = await s3.listBuckets().promise()
return buckets
}
- ES module handler
-
例 – async/await を使用した AWS SDK v3
この例では、nodejs18.x
ランタイムで使用可能な AWS SDK for JavaScript v3 を使用します。
import {S3Client, ListBucketsCommand} from '@aws-sdk/client-s3';
const s3 = new S3Client({region: 'us-east-1'});
export const handler = async(event) => {
const data = await s3.send(new ListBucketsCommand({}));
return data.Buckets;
};
コールバックの使用
コールバックを使用する代わりに、async/await を使用して関数ハンドラーを宣言することをお勧めします。いくつかの理由により、async/await の方が適しています。
-
読みやすさ: async/await コードは、コールバックコードよりも読みやすく理解しやすいです。コールバックコードは、すぐに理解するのが難しくなり、コールバック地獄に陥る可能性があります。
-
デバッグとエラー処理: コールバックベースのコードのデバッグは難しい場合があります。コールスタックを追跡するのが難しくなり、エラーが簡単に隠れてしまう可能性があります。async/await では、try/catch ブロックを使用してエラーを処理できます。
-
効率: コールバックでは、多くの場合、コードのさまざまな部分を切り替える必要があります。async/await を使用すると、コンテキストスイッチの回数を減らすことができるため、コードがより効率的になります。
ハンドラーでコールバックを使用すると、関数は、イベントループが空になるか、関数がタイムアウトするまで実行を続けます。レスポンスは、すべてのイベントループタスクが完了するまで、呼び出し元に送信されません。関数がタイムアウトした場合は、エラーが返ります。すぐにレスポンスが返るようにランタイムを設定するには、context.callbackWaitsForEmptyEventLoop を false に設定します。
コールバック関数は、Error
とレスポンスの 2 つの引数を取ります。応答オブジェクトは、JSON.stringify
と互換性がある必要があります。
次の例の関数では、URL をチェックし、ステータスコードを呼び出し元に返します。
- CommonJS module handler
-
例 – callback を使用した HTTP リクエスト
const https = require("https");
let url = "https://aws.amazon.com/";
exports.handler = function (event, context, callback) {
https.get(url, (res) => {
callback(null, res.statusCode)
;
}).on("error", (e) => {
callback(Error(e))
;
});
};
- ES module handler
-
例 – callback を使用した HTTP リクエスト
import https from "https";
let url = "https://aws.amazon.com/";
export function handler(event, context, callback) {
https.get(url, (res) => {
callback(null, res.statusCode)
;
}).on("error", (e) => {
callback(Error(e))
;
});
}
次の例では、Amazon S3 のレスポンスは、有効になるとすぐに呼び出し元に返ります。イベントループで実行されているタイムアウトは停止し、次に関数が呼び出されたときに実行を継続します。
この例を使用する前に、関数の実行ロールに Amazon S3 の読み取り許可があることを確認してください。
- CommonJS module handler
-
例 – callbackWaitsForEmptyEventLoop を使用した AWS SDK v2
この例では、Node.js 12、14、および 16 ランタイムで使用可能な AWS SDK for JavaScript v2 を使用します。
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
exports.handler = function (event, context, callback) {
context.callbackWaitsForEmptyEventLoop
= false
;
s3.listBuckets(null, callback);
setTimeout(function () {
console.log("Timeout complete.");
}, 5000);
};
- ES module handler
-
例 – callbackWaitsForEmptyEventLoop を使用した AWS SDK v3
この例では、nodejs18.x
ランタイムで使用可能な AWS SDK for JavaScript v3 を使用します。
import AWS from "@aws-sdk/client-s3";
const s3 = new AWS.S3({});
export const handler = function (event, context, callback) {
context.callbackWaitsForEmptyEventLoop
= false
;
s3.listBuckets({}, callback);
setTimeout(function () {
console.log("Timeout complete.");
}, 5000);
};