ども、@kimihom です。
今回は AWS Lambda における Node.js のコードの書き方について。
実装したいこと
例えば、id を複数持った配列があるとして、その配列を 一個一個 HTTP リクエストで叩きたい、ということがあるだろう。id単位でしかリソースを削除できないような API があった場合などは必ずそんな場面に出くわす。
これを AWS Lambda で実装するには、どうすれば良いだろうか。ここに AWS Lambda の落とし穴が潜んでいる。何も考えずに書くとこんな感じになるだろう。
var request = require('request'); exports.handler = function(event, context) { var host = "https://api.awesomeapp.com"; var ids = [1,2,3,4]; ids.forEach(function(val) { request.delete({ uri: host + "/records/" + id, json: true }, function(err, response) { context.done(); //? }); }); };
これだと当然、期待した動作にならないのはわかるだろう。 AWS Lambda は、最後まで処理を終えた時点で context.done()
を呼ばなければならず、これだと処理の途中で呼ばれてしまう。じゃあと言って、コールバック地獄の Node.js コードを書いてしまったら負けだ。非同期前提の JavaScript で頭を悩ますことになる。さて、どうすべきか。
Async を使う
AWS Lambda のドキュメントにもあるが、Async を使ってこの問題を解消させよう。最初は特殊な書き方に手こずるかもしれないが、慣れればなんとかなる。
今回は、 async.mapSeries
を利用してこの問題を解決する。
var request = require('request'); var async = require('async'); exports.handler = function(event, context) { var host = "https://api.awesomeapp.com"; var ids = [1,2,3,4]; async.mapSeries(ids, function(id, callback) { request.delete({ uri: host + "/records/" + id, json: true }, callback); }, function(err, res) { context.done(); }); };
mapSeries
は第一引数に連続処理させたいアイテムを指定する。そんで第二引数の function の id にそれぞれが渡るようになっている。 function の中で callback
を非同期に呼ぶような処理を書き、すべての ids
の配列ループが終わったら、 第三引数の function が呼ばれる。
このように書けば、すっきりと連続した 外部 API のリクエスト処理を AWS Lambda で動かすことができる!
あと たいていの Node.js ライブラリは、 コールバック引数に (error, response)
の順番で入ってくることを意識しよう。この慣習を守ることで、 Async の処理をより簡潔に記述することができる。上記コードの callback
もその仕組みを利用して省略して書くことができている。より冗長的に書くと、以下のように書くことも可能である。
request.delete({ uri: host + "/records/" + id, json: true }, function(err, res) { callback(err, res); });
async
には、mapSeries
の他に、シンプルなコールバック地獄を防ぐための waterfall
も用意されている。 AWS Lambda を Node.js で扱うには、これらのメソッドを使いこなし、すべての非同期処理が完全に終わったタイミングで、 context.done()
を呼ばなければならない。Asyncにはその他様々なコールバック操作の仕組みが用意されている。詳しくはドキュメントを参照していただきたい。
終わりに
普段 Node.js をあまり書かない人にとって AWS Lambda を使いこなすには、 Async のような非同期処理のライブラリの知識が必須とも言える。私も普段は Ruby でプログラムを書いているし、Webフロントエンドの JavaScript ではあまり複雑に非同期処理を書いたりしないため、なかなか慣れずに苦労した。本記事が AWS Lambda で Node.js を扱う方にとって有益な記事になれば幸いだ。