非同期Lambdaのコンテキストはどこ行った?
Flickr: detective (
Creator: olarte.ollie,
License: CC BY-SA 2.0 )
結局どこへも行ってなかったって結論ですがっ!
この4月からAWS Lambda で Node.js 8.10 が使えるようになっており、AWSのコンソールから新規作成するとひな型がasync関数になっています。
しかし引数リストが event
ひとつだけになっていて、従来第2引数で渡されていた context はどこに行ったの?と調べてみました。
目次
- はじめての Lambda with Node.js 8.10 は非同期関数
- ところで Lambda のコンテキストって何でしょう
- 「this === context?」って仮説は否定されました
- じゃあコンテキストはどこ行った?
- 非同期Lambdaのcallbackの扱いは?
- 結論と所感など
はじめての Lambda with Node.js 8.10 は非同期関数
現在、Node.js 8.10 のLambda を新規作成すると以下のひな型が作られます。async関数になってますね。
そして、引数が event だけ。えらいスッキリしましたね。context は何処へ?
exports.handler = async (event) => { // TODO implement return 'Hello from Lambda!' };
ところで Lambda のコンテキストって何でしょう
AWS Lambdaに渡される context は以下のキーを持つオブジェクト。 Lambda関数自体の情報を保持しています。 結構重要な情報があるはずなので、これが渡されないとはいぶかしい。
- callbackWaitsForEmptyEventLoop
- functionName
- functionVersion
- invokedFunctionArn
- memoryLimitInMB
- awsRequestId
- logGroupName
- logStreamName
- identity
- clientContext
「this === context
?」って仮説は否定されました
ジャバスクリプターが「コンテキスト」と聞いて最初に連想するのは this
ですよね(本当か?)
そこで「Node.js 8.10 のLambda関数内では、this === context
なのではないか?」と仮説を立てて、以下のLambdaを書いてみた。
exports.handler = async (event) => { return JSON.stringify({ callbackWaitsForEmptyEventLoop: this.callbackWaitsForEmptyEventLoop, functionName: this.functionName, functionVersion: this.functionVersion, invokedFunctionArn: this.invokedFunctionArn, memoryLimitInMB: this.memoryLimitInMB, awsRequestId: this.awsRequestId, logGroupName: this.logGroupName, logStreamName: this.logStreamName, identity: this.identity, clientContext: this.clientContext, }); };
で、コンソールから動かしてみたのですが、全てがnullで、仮説は完全否定されました。 まあ、そんなヤヤコシイことしないか。
じゃあコンテキストはどこ行った?
てことでAWSコンソールでしばらく探ってみたのですが、「もしやどこにも行っていないのでは?」と思い、
exports.handler = async (event, context) => { return JSON.stringify({ callbackWaitsForEmptyEventLoop: context.callbackWaitsForEmptyEventLoop, functionName: context.functionName, functionVersion: context.functionVersion, invokedFunctionArn: context.invokedFunctionArn, memoryLimitInMB: context.memoryLimitInMB, awsRequestId: context.awsRequestId, logGroupName: context.logGroupName, logStreamName: context.logStreamName, identity: context.identity, clientContext: context.clientContext, }); };
上のLambdaで確認すると、、、お見事大当たり。なんだちゃんと渡って来てるじゃないかと。
コンソールの実行結果:
非同期Lambdaのcallbackの扱いは?
じゃ、「コールバックはどこ行った?」と確認してみると、しっかり第3引数でもらってました。何も変わっちゃいなかったのね。
そして、Async なLambdaで、従来通り callback を呼び出した場合は、優先的に戻り値として採用されるようになっています。
以下のLambdaを呼び出すと "OK!"
が返されます。
exports.handler = async (event, context, callback) => { callback(null, "OK!"); return JSON.stringify({ callbackWaitsForEmptyEventLoop: context.callbackWaitsForEmptyEventLoop, functionName: context.functionName, functionVersion: context.functionVersion, invokedFunctionArn: context.invokedFunctionArn, memoryLimitInMB: context.memoryLimitInMB, awsRequestId: context.awsRequestId, logGroupName: context.logGroupName, logStreamName: context.logStreamName, identity: context.identity, clientContext: context.clientContext, }); };
結論と所感など
この調査で分かったこと:
- Node.js 8.10 の Async な Lambda にも、contextやcallbackコールバックは渡されている(単にひな型の引数リストからなくなってるだけ)。
- コールバックで解決した値が、return よりも優先的にLambdaの戻り値として採用される。
contextについて、あえて渡さないことにメリットがないので当たり前と言えば当たり前か。 自分の妙な思い込みが邪魔をしました(笑)。
コールバックの件については、古いLambdaを改造するときに、どうしても await を使いたくなったら、Node.js のランタイムバージョンを8.10に変更して、async を付け加えれるだけで済むのですね。レアケースかも知れんけど。
しかし、なんで初期状態の引数リストからcontext
を削除しちゃったのだろうかね?
callback
を、あえて示さないのは理解できるが・・・。