概要
Express (Node.js) を用いたアプリケーションを構築する場合、HTTP リクエストを受け取った直後にレスポンスを返し、その後非同期でリクエストに応じた処理を実行したいケースがあります。
var request = require('request');
router.post('/create', function(req, res, next) {
res.send({message: 'OK'});
// send data to API gateway (async)
request.post({
url: '{API_GATEWAY}',
form: JSON.stringify(req.body),
timeout: 3000
}, function(error, response, body) {
// call an undefined method
undefinedMethod();
};
});
上記例の場合、/create
をリクエストすると API_GATEWAY
への API コールが非同期で実行され、レスポンス受信時に例外をスローしています。
ただし、例外ハンドラを設定していたとしても、非同期処理で発生した例外は捕捉されない点を留意する必要があります (例外が捕捉できない理由は JavaScriptと非同期のエラー処理 が詳しい)。
非同期処理で例外が発生すると、サーバプロセスはその時点で落ちてしまいます。
ReferenceError: undefinedMethod is not defined
対策
非同期コードを try/catch
で囲う対策もありますが、ナンセンスな気もするので、ここでは Express domain ミドルウェアを使った対策を紹介します。
Express domain は Node 0.8 から導入された domain モジュールに依存します。domain モジュールの概要については クラスメソッドの記事 が分かりやすいです。
初めに express-domain-middleware を Express のプロジェクトにインストールします。
$ npm install express-domain-middleware --save
npm WARN package.json nodejs@1.0.0 No description
npm WARN package.json nodejs@1.0.0 No repository field.
npm WARN package.json nodejs@1.0.0 No README data
npm WARN package.json domain@0.0.1 domain is also the name of a node core module.
npm WARN package.json crypto@0.0.3 crypto is also the name of a node core module.
express-domain-middleware@0.1.0 node_modules/express-domain-middleware
次に app.js
を開き、ミドルウェアを登録します。ついでにエラーハンドラの設定も記載しておきます。
var domain = require('express-domain-middleware');
var app = express();
app.use(domain);
...
// exception handlers
app.use(function(err, req, res, next) {
logger.error.fatal(err);
});
それでは先ほどの /create
メソッドを再度実行してみましょう。
今度はサーバプロセスが落ちることなく、非同期処理で起きた例外が捕捉されていることが分かるかと思います。
[2015-09-11 14:21:14.157] [FATAL] error - { [ReferenceError: undefinedMethod is not defined]
domain:
{ domain: null,
_events: { error: [Function] },
_maxListeners: undefined,
members: [ [Object], [Object] ],
id: 1441948872626 },
domainThrown: true }
ReferenceError: undefinedMethod is not defined
...