I'm wrapping some async executed 'child'-functions in an async.forEach construct (from the great lib: https://github.com/caolan/async)
When one of these child-functions fails with an uncaught exception the entire node-process hangs. (since a callback is never returned to the async.forEach construct, async.forEach still thinks a child-function is busy)
However I would have thought at least the thrown exception would bubble up, since I'm not catching it anywhere. Is there a way to configure how async.forEach handles these exceptions? It's really hard programming against this.
Solved. For future reference:
OK so I basically had this:
var async = require("async");
var cb = function(){
//denote done to async.foreach
}
async.forEach(defaultFunctions,function(defaultFunc,cb){
defaultFunc(cb);
},callback);
The problem was that when a certain defaultFunction throws an uncaught exception, the exception is swallowed by async.forEach
. Moreover there's no way to catch it in the calling context.
The result is severe: complete halt of the parent node-process, without any trance what's causing it.
In the called context (i.e: the defaultFunction that throws the exception) I could of course meticulously try to catch all exceptions, but these functions are hot-pluggable, possibly ranging in the hundreds in the end and I don't want to burden each of these functions with 100% full-proof error-handling.
A solution I've found is to use promises (using the Q library -> github.com/kriskowal/q ) to wrap the functions in:
var async = require("async")
var Q = require("q");
var cb = function(){
//denote done to async.foreach
}
async.forEach(defaultFunctions,function(defaultFunc,cb){
var obj = {
defaultFunc: defaultFunc
}
return Q.ncall(obj.defaultFunc,obj)
.then(function(result){
return cb() ;
}fail(function(err){
return cb(err); //ANY thrown uncaught error in obj.defaultFunc will get
//caught and changed to a correct callback as needed
//for async.forEach
}
},callback);
Of course, now I realize async.foreach can be done trivially with Q.promises instead but that's another story...