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.
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.
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
@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
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.
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