先週、AWS Lambdaのアップデートがされましたね!
【AWS発表】AWS Lambda – モバイル開発のための新機能とともに全てがプロダクションに
同期呼び出しがサポートされたことで、これでまともに2Tierとして使えるようになりました。
でも、context.succeed
とcontext.fail
って、どういう挙動させるんだろう?と気になったのでcontext
の中身を調べてみました。
前バージョンのcontext
の中身は下記を参照してください。
検証コード
exports.handler = function(event, context) {
console.log(context);
console.log(context.__proto__);
console.log('awsRequestId', context.awsRequestId);
console.log('invokeid', context.invokeid);
console.log('logStreamName', context.logStreamName);
console.log('succeed()', context.succeed.toString());
console.log('fail()', context.fail.toString());
console.log('done()', context.done.toString());
context.done(null);
};
一度、context
をconsole.log
で出力して、表示された値をそれぞれ出力してあげる感じです。
出力結果
START RequestId: 09ecd985-e0ca-11e4-84c0-8b4f359a82ec
2015-04-12T04:11:49.738Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec { awsRequestId: '09ecd985-e0ca-11e4-84c0-8b4f359a82ec',
invokeid: '09ecd985-e0ca-11e4-84c0-8b4f359a82ec',
logStreamName: '2015/04/12/d76c581c256a434985cfe529e6274b64',
succeed: [Function],
fail: [Function],
done: [Function] }
2015-04-12T04:11:49.797Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec {}
2015-04-12T04:11:49.797Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec awsRequestId 09ecd985-e0ca-11e4-84c0-8b4f359a82ec
2015-04-12T04:11:49.797Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec invokeid 09ecd985-e0ca-11e4-84c0-8b4f359a82ec
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec logStreamName 2015/04/12/d76c581c256a434985cfe529e6274b64
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec succeed() function (result) {
checkExpectedArgRange('succeed', arguments, 0, 1);
if(isUndefined(result)) {
result = null;
}
try {
result = JSON.stringify(result);
finish_event_invoke(null, result);
} catch(err) {
var errorObject = failParamToErrorObject(err)[1];
errorObject['errorMessage'] = "Unable to stringify body as json: " + errorObject['errorMessage'];
fail_event_invoke('unhandled', errorObject);
}
}
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec fail() function (error) {
checkExpectedArgRange('fail', arguments, 0, 1);
var multi_result = failParamToErrorObject(error);
fail_event_invoke(multi_result[0], multi_result[1]);
}
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec done() function () {
checkExpectedArgRange(arguments, 0, 2);
if(isUndefinedOrNull(arguments[0]) && isUndefinedOrNull(arguments[1])) {
_this.succeed();
} else if (isUndefinedOrNull(arguments[0])) {
_this.succeed(arguments[1]);
} else if (isUndefinedOrNull(arguments[1])) {
_this.fail(arguments[0]);
} else {
//support backwards compatibility by logging message here
console.log("Error Message: " + arguments[1]);
_this.fail(arguments[0]);
}
}
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec result: null
END RequestId: 09ecd985-e0ca-11e4-84c0-8b4f359a82ec
REPORT RequestId: 09ecd985-e0ca-11e4-84c0-8b4f359a82ec Duration: 176.25 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 9 MB
出力結果を見てみるといくつかのプロパティ、メソッドが追加されて、ログにも結果出力のログが増えてますね。
それぞれを細かくみていきます。
context.logStreamName
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec logStreamName 2015/04/12/d76c581c256a434985cfe529e6274b64
ログストリームの名前が引き渡させるようになりました。
全く使い道がわかりませんが、このタイミングでログストリームの名前が確定されるということは、実行後にログを取得するときに待つ必要がなくなったのでは!?
まだ検証してませんがコマンドラインで実行→ログ取得を高速に回せるようになっていると良いなぁと思います。
context.succeed
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec succeed() function (result) {
checkExpectedArgRange('succeed', arguments, 0, 1);
if(isUndefined(result)) {
result = null;
}
try {
result = JSON.stringify(result);
finish_event_invoke(null, result);
} catch(err) {
var errorObject = failParamToErrorObject(err)[1];
errorObject['errorMessage'] = "Unable to stringify body as json: " + errorObject['errorMessage'];
fail_event_invoke('unhandled', errorObject);
}
}
同期呼び出しのサポートで追加された、成功時にレスポンスを返すメソッドです。
succeed
にJSON変換可能な値を渡すとJSONに変換してレスポンスを返してくれるようになるようです。
そのため、それ以外のフォーマットでレスポンスを返すというのはできなさそうですね。
JSON変換成功時に呼び出しているfinish_event_invoke
はグローバルな関数ではなく、succeed
のスコープに隠蔽されているのでこのあたりを拡張するのは無理そうです。
context.fail
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec fail() function (error) {
checkExpectedArgRange('fail', arguments, 0, 1);
var multi_result = failParamToErrorObject(error);
fail_event_invoke(multi_result[0], multi_result[1]);
}
こちらも同期呼び出しのサポートで追加された、失敗時にレスポンスを返すメソッドです。
failParamToErrorObject
で前のcontext
のようにエラーの有無と、エラーメッセージ(or オブジェクト)に変換してfail_event_invoke
渡しているのかなと妄想しますが、実際のところよくわかっていないです。
AWSの中の人にこのあたりの実装を聞きたいですね。
context.done
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec done() function () {
checkExpectedArgRange(arguments, 0, 2);
if(isUndefinedOrNull(arguments[0]) && isUndefinedOrNull(arguments[1])) {
_this.succeed();
} else if (isUndefinedOrNull(arguments[0])) {
_this.succeed(arguments[1]);
} else if (isUndefinedOrNull(arguments[1])) {
_this.fail(arguments[0]);
} else {
//support backwards compatibility by logging message here
console.log("Error Message: " + arguments[1]);
_this.fail(arguments[0]);
}
}
前のバージョンからあったcontext.done
ですが実装が内部でsucceed
とfail
を呼び出す形に変更されています。
そのため、既存の実装でも同期呼び出しは扱えそうですね。
context.done(); //-> succeed
context.done(null, 'success'); //-> succeed
context.done(undefined, 'success'); //-> succeed
context.done('fail'); //-> fail
context.done('fail', null); //-> fail
context.done('fail', undefined); //-> fail
context.done(true, 'fail'); //-> fail
だいたいdone
の呼び出しはこんな感じですね。
まぁ、実装的にはこれまで通り、第一引数にエラーの有無を渡して、第二引数にエラーメッセージ(or オブジェクト)を渡すので良さそうです。
result log
2015-04-12T04:11:49.798Z 09ecd985-e0ca-11e4-84c0-8b4f359a82ec result: null
ついでにログの種類も増えていて、レスポンスとして返される値もログに出力されるようになったようです。
正直、エンジニアが見てはいけない値(個人情報系とか)をレスポンスで返す可能性を考えると、これはちょっとオフにしたい・・・。
error log
START RequestId: 1ccb67ee-e0cc-11e4-bc7a-139cb7123bb7
Failure while running task: ReferenceError: finish_event_invoke is not defined
at exports.handler (/var/task/index.js:2:17)
Process exited before completing request
ReferenceError: finish_event_invoke is not defined
END RequestId: 1ccb67ee-e0cc-11e4-bc7a-139cb7123bb7
REPORT RequestId: 1ccb67ee-e0cc-11e4-bc7a-139cb7123bb7 Duration: 221.85 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 9 MB
ちなみに構文エラーや、エラーをキャッチしなかった場合は上記のようなログになります。
まとめ
調査も完了したので、これから自作のlambda-handlerというモジュールのアップデート作業に入ります。正直、面倒臭いです。
Lambda functionの第一引数に渡すjsonを指定したり、requireしているモジュールをモック化してLambda functionを呼び出す便利なモジュールが欲しい・・・。
追記
/var/runtime/node_modules/awslambda/bin/awslambda
/var/runtime/node_modules/awslambda/lib/awslambda.js
に実行系とコードがあるの見つけました。
AWS Lambdaで実行前と実行後にどうしているの気にしている人はここをcatしたりすると幸せになるかもしらんです。