AWS
lambda

AWS Lambdaのための関数のローカル開発とテスト

More than 3 years have passed since last update.

これは個人の意見/メモであり、所属する組織を代表するものではありません。


サマリ

AWS LambdaのLambda Funcitonをローカルで開発する環境について考えてみた。

なお、このポストの続きをAWS Lambdaの関数をnpmでパッケージ管理に書いています。


大まかな方法

Lambdaでは、例えば以下のような感じで関数を実装してアップロードする。


myFirstLambda.js


var AWS = require("aws-sdk");
var DOC = require("dynamodb-doc");

AWS.config.update({region: "us-west-2"});

exports.handler = function(event, context){
this.docClient = new DOC.DynamoDB();

//Do something with DynamoDB

context.done();
}


で、実行の際にはmyFirstLambda.jsがrequireされてhandlerメソッド(メソッド名はLambdaの設定で変更可能)が呼ばれる、という非常に単純な話(少なくとも外から見る限り)なので、以下のようなドライバスクリプトを書いてあげればOK。


driver.js


//YOUR DATA TO BE PASSED TO LAMBDA FUNCTION.
var event = {
"Records": [
{
"awsRegion": "us-west-2",
"sequenceNumber": "196800000000000000000374",
"partitionKey": "2efdb0ea22685b46993e42a67302a001",
"eventSource": "aws:kinesis",
"data": "SOME CUSTOM DATA 1"
}
]
};

//BUILD STAB OF context OBJECT.
var context = {
invokeid: 'invokeid',
done: function(err,message){
return;
}
};

//RUN YOUR HANDLER
var lambda = require("../myFirstLambda");
lambda.handler(event,context);



handlerに渡ってくるeventとcontextというオブジェクトについての補足



  • event: 実際に渡ってくるイベントのデータ(S3のアップデートとかKinesisのレコードとか)。


  • context: Lambda functionの呼び出しコンテキスト。done()というAPIを呼び出すと関数が終了するのだが、コードをちょっと追いきれてないのでとりあえず単純にreturnするだけな感じにstub化。ちなみにcontextオブジェクトのダンプは以下のとおり。done()の中で呼び出されているpostDone()は後で追ってみる。


{
invokeid: 'STRING', // Lambda functionの呼び出しIDのようなもの(恐らく呼び出しごとにユニーク)
done: function (err, message) {
if(doneStatus) {
return;
}
doneStatus = true;
var error = null;
if(!(typeof err == "undefined" || (typeof err == "object" && !err))) {
error = util.format(err);
console.log(error);
}
/*
* use a timeout to perform the operation once the user gives up control of the event thread
* This is how HTTP handler works right now
*/
setTimeout(function() {
postDone(error, message);
}, 0);
}
}

というわけで、こんな感じにドライバスクリプトを準備してあげれば、コード書いてLambdaにアップしてSave & Invokeして・・・みたいなのを繰り返さずにもローカルで開発ができるよという話でした。


テストを書く

ドライバが書けたので、ちょっと手を加えればテストも書ける。


test/basic.js

var assert = require('assert');

//YOUR_EVENT_OBJECT
var data = {};

var context = {
invokeid: 'invokeid',
done: function(err,message){
return;
}
};

describe('myFirstLambda',function(){
it('Should have docClient', function(){
var lambda = require("../myFirstLambda");
lambda.handler(data,context);
assert(lambda.docClient);
});
});


で、package.jsonにこんな感じにテスト実行と依存関係について定義しておけばLambda用の関数をnpmパッケージとして 管理できる・・・気がする。


package.json



{
"name": "myFirstLambda",
"version": "0.0.1",
"private": true,
"dependencies": {
"aws-sdk":"2.*",
"dynamodb-doc":"1.*"
},
"devDependencies": {
"mocha": "*",
"eslint": "*",
"istanbul": "*"
},
"scripts" : {
"test" : "npm -s run-script lint && npm -s run-script unit",
"unit" : "istanbul `[ $COVERAGE ] && echo 'cover _mocha' || echo 'test mocha'` -- test test/basic",
"lint" : "eslint ./*.js"
}
}


あとはscriptに


  • build: 必要なファイルをzipしてpkg/配下に吐き出す

  • deploy: AWS Lamdaにアップロードする

あたりを付け足してあげるとよりパッケージ管理が楽になりそうなんだけど、それはまた今度。


追記

続き書いた: AWS Lambdaの関数をnpmでパッケージ管理