Unable to handle exception with node.js domains using express

大城市里の小女人 提交于 2019-11-27 15:59:03

问题


I want to use Node.js Domains to catch exceptions. It is working so far, but there is one place I can't get domains to catch the exception. exception2 in the callback is caught and handled in the domain.on('error') handler, but exception1 is not caught. The odd thing is that when exception1 is thrown, it doesn't shutdown Node like I would expect. Here is my example app:

var domain = require('domain');
var request = require('request');
var express = require('express');

var serverDomain = domain.create();
serverDomain.on('error', function(err) {
  console.log("Server Domain Error: " + err);
});

var app;

serverDomain.run(function() {
  app = express();
  app.listen(3000);
});

app.use(function(req, res, next) {

  var reqDomain = domain.create();
  reqDomain.add(req);
  reqDomain.add(res);
  reqDomain.on('error', function(err) {
    console.log("Req Domain Error: " + err);
    reqDomain.dispose();
    next(err);
  });

  next();
});

app.get('/', function(req, res) {
  var uri = "http://google.com";

  exception1.go();

  request.get({url:uri, json: {}},
    function (error, response, body) {
      if(response.statusCode === 200) {
        exception2.go();
        res.send('Success getting google response');
      }
    });
});

To get exception2 to execute, I comment out exception 1.


回答1:


The problem is that the exception happens during Connect's routing, which has both a try/catch block around its execution, as well as a default error handler which prints out stack trace details when running in a non-production mode. Since the exception is handled inside of Express, it never reaches your outer layer for the domains to handle.

How it differs from exception2 is that the handler function for the '/' route is executed directly by that Connect block, in the same stack as the original call that went through Express. The second exception occurs in a callback, after some I/O operation has returned, and therefore is executed by a stack originating from Node's event loop I/O handler, and so the try/catch of Express isn't available to snag that exception and save the app server. In fact, if you comment out all the domain stuff, and trip exception2 it crashes Node.

Since only unhandled exceptions are routed to the domain mechanism, and since exception1 has a try/catch visible in it's call stack above it, the exception is handled, and not forwarded to the domain.




回答2:


Connect-domain allows you to catch all errors for connect modules including express.

Connect-domain https://github.com/baryshev/connect-domain

The example for express3: http://masashi-k.blogspot.com/2012/12/express3-global-error-handling-domain.html




回答3:


@user1007983

No, in production, the try/catch handling still exists in Connect/Express. The way to solve it is to add your own try/catch block in the "root" which you can then use to emit an "error" event to the domain before connect sends the error response.

try {
    // .. code here ..
} catch (err) {
    domain.emit('error', err);
}

Another way to get around it is to just disconnect from the handler, like wrapping your code in a setImmediate block




回答4:


I've tried try/catch blocks (which may not work the way you think with async code). I've tried node domains in several different ways. But I was unable to handle an exception thrown in a 3rd party lib (sequelize). Why did I get the exception? Well, it was because the SQL that was generated was not well formed. (My fault).

Anywho, the solution that worked best for me and my (small) project was to use forever. Let the exceptions happen, but fire up node again if they do. I doubt it is the most elegant solution, but it works for me and my small project.

With a larger project, domains combined with the clustering API might be a good choice.

Winston is another choice. It might be cool to combine forever with winston so that if you DO get an exception, you can have winston email you, so you can fix the code. Meanwhile, forever will happily restart the app for you.




回答5:


I came across this problem while testing my domain-based error handling.

I went with the approach suggested here by Issac, with a couple of minor changes: use 'domain.active' to get the currently active domain and emit the error event on that, and I used a wrapper function to avoid having to modify all of my handler functions:

domainWrapper = function(func) {
    return function(req, res) {
        try {
            return func(req, res);
        } catch (err) {
            domain.active.emit('error', err);
        }
    }
}

Then changed this sort of thing:

app.get('/jobs', handlerFunc);

to this:

app.get('/jobs', domainWrapper(handlerFunc));


来源:https://stackoverflow.com/questions/13228649/unable-to-handle-exception-with-node-js-domains-using-express

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!