11

Is it possible to wrap every request coming through express.js in a domain or trycatch see trycatch info here?

I am trying to create a 'catch all' of sorts (the express error handler middleware does not catch async calls) to be sure any errors I miss are handled with a 500 being sent to the user.

If you have an asynchronous function call (eg. process.nextTick()), then it will be outside the scope of express' error handler, thus killing the process entirely. Thus, using the express error handler will not work in all cases.

Ben Zuill-Smith
  • 3,504
  • 3
  • 25
  • 44

1 Answers1

10

Express already has error handler implementation. It inherit it from connect. To use it you need to add it as the last middleware point (last app.use(...) call). For example:

var express = require('express')
  , app = express();

app.use(app.router);
app.use(express.errorHandler());

// app.get(...), app.post(...), app.listen(...), etc.

If you want to handle all errors with simple 500 response code, you could replace express.errorHandler() with you own function. In that case your code will looks like:

var express = require('express')
  , app = express();

app.use(app.router);
app.use(function(err, req, res, next){
  if (!err) return next();
  res.send(500);
});

// app.get(...), app.post(...), app.listen(...), etc.

More information about that way could be found in express error example comments in code

UPDATE:

Of course you could use domain for each request. You could wrap each request separately or use wrapping for router to handle ALL exceptions. Code is following:

var express = require('express')
    , http = require('http')
    , app = express()
    , domain = require('domain');

//app.use(app.router);
app.use(function(req, res, next){
    var d = domain.create();
    d.on('error', function(er) {
        console.log('error, but oh well', er.message);
        res.send(500);
    });

    // explicitly add req and res
    d.add(req);
    d.add(res);

    d.run(function() {
        app.router(req, res, next);
    });
});

app.get('/', function(req,res){
    process.nextTick(function(){
        throw new Error('Check Error');
    });
});

http.createServer(app).listen(3000, function(){
    console.log('Express server listening on port 3000');
});

!!BUT!! never use this in production. The reason of that is in nature how JS throw work. It will definitely be a cause of leaking in your application and make it even more unstable. You could use such error handling to implement custom algorithm of shutdown (for example to close already opened connection). More information about right use of domain could be found in documentation.

To monitor the leaking you could use the technique from this article.

UPDATE 2:

I just can't leave this not finished. trycatch code:

var express = require('express')
    , http = require('http')
    , app = express()
    , domain = require('domain')
    , trycatch = require('trycatch');

//app.use(app.router);
app.use(function(req, res, next){
   trycatch(function(){
           app.router(req, res, next);
       }, function(er){
           console.log(er.message);
           res.send(500);
       });
});

app.get('/', function(req,res){
    process.nextTick(function(){
        throw new Error('Check Error');
    });
});

http.createServer(app).listen(3000, function(){
    console.log('Express server listening on port 3000');
});

I had review the source of trycatch and there was no any magic. It still be cause of leaks. trycatch has domain under the hood.

andbas
  • 591
  • 4
  • 8
  • 1
    Sorry, this doesn't cover all cases. I'll edit the question to mention I've already considered this. If you have an asynchronous function call (eg. process.nextTick()), then it will be outside the scope of express' error handler, thus killing the process entirely. There are such things as ```domains``` and the ```trycatch``` module that mitigate this issue, but I'm not sure how to wrap an express request in a domain or trycatch. – Ben Zuill-Smith Oct 30 '13 at 22:18
  • I have update my answer. Of course you could, but I don't think that this's a good idea. Probably you'll like to use customization in shutdown and something like [forever](https://github.com/nodejitsu/forever) to make your script runs continuously – andbas Oct 31 '13 at 08:44
  • trycatch does a lot of shimming in the core libraries to prevent leaks and other problems. Thanks for the code. Not sure if I can accomplish the same with trycatch but I guess I take that discussion to the trycatch repo – Ben Zuill-Smith Nov 01 '13 at 20:25
  • Zuill, to help you I had add the trycatch example, but please remember - trycatch is not a silver bullet, it's still use domain and can't prevent leaks. – andbas Nov 01 '13 at 21:43
  • 1
    In Express 4 : Error: Most middleware (like errorHandler) is no longer bundled with Express and must be installed separately. – Husky Apr 18 '15 at 06:41
  • Can this code: `d.run(function() { app.router(req, res, next); });` be replaced with this one: `d.run(next)`? – Eugene Mala May 16 '15 at 10:04
  • 1
    `app.router(req, res, next);` is deprecated in Express 4.x – Eugene Mala May 16 '15 at 10:28
  • 1
    @andbas Is it advisable to use domain? The official docs say that it is going to be deprecated. What are the other ways to do error handling in node js? – inertia Jun 03 '16 at 13:07