これは個人の意見/メモであり、所属する組織を代表するものではありません。
サマリ
AWS LambdaのLambda Funcitonをローカルで開発する環境について考えてみた。
なお、このポストの続きをAWS Lambdaの関数をnpmでパッケージ管理に書いています。
大まかな方法
Lambdaでは、例えば以下のような感じで関数を実装してアップロードする。
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。
//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して・・・みたいなのを繰り返さずにもローカルで開発ができるよという話でした。
テストを書く
ドライバが書けたので、ちょっと手を加えればテストも書ける。
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パッケージとして 管理できる・・・気がする。
{
"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でパッケージ管理