Can domains be nested in node.js? - node.js

With synchronous errors, you can nest error scopes like this:
try {
try {
throw Error('e')
} catch(e) {
if(e.message !== 'f')
throw e
}
} catch(e) {
handleError(e)
}
This is how I would expect it to work, but it doesn't (seems an error inside a domain error handler is thrown up to the top, skipping any domains in between):
var domain = require('domain');
var dA = domain.create();
dA.on('error', function(err) {
console.log("dA: "+ err); // never happens
});
dA.run(function() {
var dB = domain.create();
dB.on('error', function(err) {
throw err
});
dB.run(function() {
setTimeout(function() {
console.log('dB')
throw 'moo'
},0)
});
});
Is there a way to do this right?

Bubbling doesn't work in domains through rethrowing. If you want to pass an error off to another domain you know can handle an error, you can re-emit the error event on that domain directly:
var domain = require('domain');
var dA = domain.create();
dA.on('error', function(err) {
console.log("dA: "+ err); // never happens
});
dA.run(function() {
var dB = domain.create();
dB.on('error', function(err) {
dA.emit('error', err);
});
dB.run(function() {
setTimeout(function() {
console.log('dB')
throw 'moo'
},0)
});
});
To expand a little, the problem with throwing from a domain's error handler is that it propagates directly to the top level, and even more confusingly, if the throw is the result of an error in the error handlier, is that the stacktrace that gets printed out is from your original error, not the new error in the handler. Theoretically it would be possible to bubble exceptions up the stack, but that's not how domains were designed.
The "nested" domains will work properly if the handler of an outer domain throws while an inner domain is active, but what it does in that case is give the error to the outer domain's error handler and then exits both the outer and the nested domain. This mimics how a catch unwinds the stack in the try/catch case, but it can be a little confusing.

Related

setTimeout() in Node.js

I am writing cloud functions on Cloud Firestore triggers. What I want is when a document is added under some uuid it has to deleted after 2 minutes and assign the same data to another document. I wrote some code regarding that like below
exports.createdOpenOrder = functions.firestore.document('Some/{psId}/Open/{OrderId}').onCreate((snap, context) => {
// Get an object representing the document
console.log("Deleting function execution started:");
const newValue = snap.data();
var OrderId = context.params.OrderId;
var psId = context.params.psId;
setTimeout(delete_cur, 120000);
function delete_cur() {
var data = db.collection('Some').doc(psId).collection('Open').doc(OrderId).delete().then(function() {
console.log("Document successfully deleted!");
// calling another function to reassign
reassign(OrderId);
return;
}).catch(function(error) {
console.error("Error removing document: ", error);
return;
});
}
});
Now my problem is the setTimeout function is not calling exactly after 2 minutes and data is not deleting. Is anything wrong with my code? Please let me know how to write code work perfectly on setTimeout.
To find the problem, put log before, and a catch around, the contents of your setTimeout handler.
Currently you are only trapping exceptions after the delete async function returns. All other exceptions in the chain, before calling delete, are not caught.
function delete_cur() {
console.log('handler called')
try {
var data = db.collection('Some').doc(psId).collection('Open').doc(OrderId).delete().then(function() {
console.log("Document successfully deleted!");
// calling another function to reassign
reassign(OrderId);
return;
}).catch(function(error) {
console.error("Error removing document: ", error);
return;
});
} catch (e) {
console.error('could not invoke delete', e)
}
}

How to produce errors\exceptions in callback functions in mongoose for testing purpose

I am working with MongoDB using Mongoose. Most of the opeartion works with callback. An error may occur while saving/updating/finding a document. Though we can always check if there an error in callback function (as shown in below code) but I want to know while developing how can we generate error and test these blocks?
Tank.findById(id, function (err, tank) {
if (err) return handleError(err);
tank.size = 'large';
tank.save(function (err) {
if (err) return handleError(err);
res.send(tank);
});
});
Are you familiar with the Error class? Emiting errors with the EventEmitter? Throwing errors with throw?
This link is a fairly extensive overview on how to deal with errors in node.
Assuming your using express, in the case of the example you provided, I would usually create an instance of the Error class doing something like:
exports.findTankById = function(req, res, next) {
var id = req.params.id;
Tank.findById(id, function (err, tank) {
if (err) {
var e = new Error("Failed to find tank");
e.data = err;
// attach other useful data to error class instance
return next(e);
}
return res.status(200).json({ data: tank });
})
});
Then in another part of the application, have a middleware function that catches errors passed by your routes via next(). That function could log the error or doing something more creative. Note that when using new Error(...) you can access the stack using the stack attribute of the Error class (e.g. err.stack). After processing the error, the error handler function would send back an appropriate response.
A simple error handler function could look something like:
app.use(function (err, req, res, next) {
if(err.data) {
// caught operational errors
/* do something to log or process error */
var response = {
type : 'error',
description : err.message // this would use "Failed to get tank" for above example
};
res.status(500).json(response);
} else {
// unexpected errors
var domainThrown = err.domain_thrown || err.domainThrown;
var msg = 'domainThrown: ' + domainThrown + '\n' + err.stack;
console.error('%s %s\n%s', req.method, req.url, msg);
res.set('Connection', 'close');
res.setHeader('content-type', 'text/plain');
res.status(503).send(msg + '\n');
}
});
If you like this approach, I usually define more specific error objects of my own that more or less extend the Error class. Using functions to create the more specific error types limits the need to write out the
var e = new Error("Failed to find tank");
e.data = err;
/* attach other useful data to error class instance */
part every time. Using more specific error objects also forces consistency on how the errors are being formatted. Hope that is helpful,
Craig

propagating error from a callback in nodes

I'm a newbie as far as node is concerned, so what i am asking here might be plain out stupid, so bear with me.
Below is the code for a node module that connects to a given mongodb database, my problem is on line19 where i am trying to throw the error in case the connection to the db server cannot be made or the db server is down, but node complains , please advise.
Code:-
var dbinit_func = function(db_name){
try{
// require mongoose , if it's not there
// throw an exception and but out
var mongoose = require('mongoose');
}
catch(err){
throw "Error Mongoose Not Found"
}
try{
// connect to the db
mongoose.connect("mongodb://localhost/" + db_name);
// get a reference to the connection object
var db_connection = mongoose.connection;
// subscribe to events on the connection object
db_connection.on('error', function(err){
// holy cow "A Connection Error", shout it out loud
// and but out
throw new Error(err.message);--> This is where the problem Occurs
});
// bind to the connection open event , we just need to
// do it once , so we use the once method on the
// connection object
db_connection.once('open', function(){})
}
catch(err){
// we got an error most probably a connection error
// so we but out from here
throw "Connection Error";
}
}
module.exports = dbinit_func;
Message spitted by Node:-
/Users/tristan625/projects/node_projs/school_web/models/db.js:19
throw new Error(err.message);
^
Your code is written in a synchronous style, as seen by the try/catch blocks. What you must understand, is that the mongoose.connect function is asynchronous. When you call throw new Error(), that call will occur inside of a callback, which is outside the scope of your try/catch blocks, hence you can't handle the error using them.
Your dbinit_func must be written to allow for a callback
Here's a pretty standard way of doing what you're doing
function dbinit_func(db_name, callback) {
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/ + db_name', { auto_reconnect: true });
var db = mongoose.connection;
db.once('error', function(err){
//trigger callback with an error
callback(err);
});
db.once('open', function() {
//trigger callback with success
callback(null, 'DB Connection is open');
});
}
module.exports = dbinit_func;
// to call this function, you'd want to do something like this
var dbinit = require('/path/to/your/module');
dbinit('mydatabasename', function(err, res){
// at this point, there will either be an error
if (err) console.log(err.message);
// else it will be success
console.log(res);
});

Nodeunit: Runtime/thrown errors in test function are _silent_

One of the points of using NodeUnit is to write new functions and test them often. Problem is, if one of the tested functions throws an error (including JS runtime errors), the error is not shown to the user.
Here is the simplest possible test case: (Note that a.b.c.d will cause a runtime error)
exports.all = {
one: function( test ){
test.done();
},
two: function( test ){
as( function( err, res ){
test.done();
});
},
}
function as( callback ){
process.nextTick( function() {
a = testMe();
callback( null, a );
});
}
function testMe(){
a.b.c.d.e = 100;
return 10;
}
However, testMe() might be a new function I am developing. An uninitialised variable, or anything, will just fall silent.
Add your own uncaught exception handling to your test file either via the uncaughtException event:
process.on('uncaughtException', function(err) {
console.error(err.stack);
});
Or by creating a domain and adding process to it (or whatever event emitter(s) your tests use) so that you can catch the errors that occur within your use of process.nextTick:
var dom = require('domain').create();
dom.add(process);
dom.on('error', function(err) {
console.error(err.stack);
});
Either way, you'll then get console output that looks like:
ReferenceError: a is not defined
at testMe (/home/test/test.js:24:3)
at /home/test/test.js:18:9
at process._tickDomainCallback (node.js:459:13)

Possible binding loss in Expressjs?

so I am running into what I think is a binding issue, caused by connect-mongo or expressjs Here is the code:
//Error
app.use(function(err, req, res, next) {
if (err instanceof noData) {
res.send(err, 404);
} else {
next(err);
}
});
My custom error handler
function noData(err){
this.code = 0;
this.msg = err;
console.log(Error);
Error.call(this, {code:0, msg:err});
Error.captureStackTrace(this, arguments.callee);
};
noData.prototype.__proto__ = Error.prototype;
Throwing error here:
err = true;
//if(err) throw new noData('No Password');
//Get user from database
db.collection('users').find({}, {limit:1}).toArray(function(err, result) {
if(err) throw new noData('No Data');
});
The first error throws correctly, but the second one but the second one throws a general nodejs error.
throw e; // process.nextTick error, or 'error' event on first tick
What am i doing wrong here? Is connect-mongo causing it to lose binding somehow?
Any thoughts are greatly appreciated.
The problem doesn't lie in express or connect-mongo, the callback is in a different scope. To resolve this simply add a (this) to the end of the call.
//Get user from database
db.collection('users').find({}, {limit:1}).toArray(function(err, result) {
if(err) throw new noData('No Data');
}(this));
Now node knows about my custom error. (hallelujah)
This essentially an iife which allows me to pass in a param.

Resources