LoginSignup
25
18

More than 5 years have passed since last update.

Expressで非同期処理中の例外をハンドリングする

Last updated at Posted at 2015-09-11

概要

Express (Node.js) を用いたアプリケーションを構築する場合、HTTP リクエストを受け取った直後にレスポンスを返し、その後非同期でリクエストに応じた処理を実行したいケースがあります。

Node.js
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と非同期のエラー処理 が詳しい)。

非同期処理で例外が発生すると、サーバプロセスはその時点で落ちてしまいます。

server_log
ReferenceError: undefinedMethod is not defined

対策

非同期コードを try/catch で囲う対策もありますが、ナンセンスな気もするので、ここでは Express domain ミドルウェアを使った対策を紹介します。
Express domain は Node 0.8 から導入された domain モジュールに依存します。domain モジュールの概要については クラスメソッドの記事 が分かりやすいです。

初めに express-domain-middleware を Express のプロジェクトにインストールします。

shell
$ 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 を開き、ミドルウェアを登録します。ついでにエラーハンドラの設定も記載しておきます。

Node.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 メソッドを再度実行してみましょう。
今度はサーバプロセスが落ちることなく、非同期処理で起きた例外が捕捉されていることが分かるかと思います。

application_log
[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
...
25
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
18