Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error thrown from a mongoose-promise callback function is not caught

I spent too much time trying to figure out why my express.js controller did not respond to a simple query, and figured out that runtime errors fired from a Mongoose-promise callback were silently interrupting the callback process.

Here is a simplified version of my code:

server.get('/api/test', function (req, res, next) {
  User.find({}).exec().then(function success(users){
    console.log('SUCCESS');  
    typo[0] = 1; // throws a runtime error
    res.json(users);
  }, function error(err){
    console.log('ERROR');  
    res.json({error: err});
  });
});

This results in SUCCESS showing up in my console, but nothing happens then. No response is given to the user, the error caused by my typo is not appearing in my console, and the error callback is not called either.

I am aware that one should not throw exceptions from a callback function, but in that case, this was just a typo, and it would make sense to me to be warned (e.g. a stack trace in my standard output) whenever one makes this kind of mistake. (we're humans, after all...)

In your opinion, what's the best way to get feedback whenever this kind of mistakes are made in promise callbacks?

like image 715
Adrien Joly Avatar asked Apr 22 '15 10:04

Adrien Joly


People also ask

Does Mongoose connect return a Promise?

You don't handle a Promise with a callback: mongoose call you're callback if provided, otherwise it return the Promise.

What is callback and Promise in Nodejs?

A promise is basically an advancement of callbacks in Node. In other words, a promise is a JavaScript object which is used to handle all the asynchronous data operations. While developing an application you may encounter that you are using a lot of nested callback functions.

How do I use promises in node JS?

Consuming a promise For example, when we request data from a server via an API that returns a promise, we utilize the then() and catch() methods to consume whatever data is delivered. In the above code, the then() method is executed when the promise is fulfilled by the resolve() callback.

What is callback function in node JS?

A callback is a function which is called when a task is completed, thus helps in preventing any kind of blocking and a callback function allows other code to run in the meantime. Callback is called when task get completed and is asynchronous equivalent for a function.


2 Answers

This is Mongoose's fault for using a bad promise implementation. Promises are throw-safe so exceptions are caught (so they can be later handled by future code) - the future code never comes and Mongoose never reports that it did not. Good promise implementations do not suffer from this issue.

Your options are two:

Use a library like Bluebird:

var Promise = require("bluebird");
var mongoose = Promise.promisifyAll(require("mongoose"));

User.findAsync({}).then(function(data){
    JSON.prase("dsa"); // not a silent failure, will show up, easy debugging
});

This has the advantage of being faster than mongoose promises so there is no performance penalty. Alternatively, if you're super conservative and don't want the performance and API gains of bluebird - you can use native promises:

// Promise is the native promise
Promise.resolve(User.find({}).exec()).then(function(data){
    JSON.prase("dsa");
});

And then, assuming you're running a modern variant of nodejs (read: io.js v 1.4.1 or upper), you can subscribe to promise rejections:

process.on("unhandledRejection", function(p, why){
    console.log("FOUND ERROR!!!!", p , why);
});

So exceptions are not silently suppressed.

like image 189
Benjamin Gruenbaum Avatar answered Oct 09 '22 08:10

Benjamin Gruenbaum


The exec() has two promises

.then(function) 
.then(null , function)

try this, I think it will help

server.get('/api/test', function(req, res, next) {
    User.find({}).exec()
        .then(function success(users) {
            console.log('SUCCESS');
            typo[0] = 1; // throws a runtime error
            res.json(users);
        })
        .then(null, function error(err) {
            console.log('ERROR');
            res.json({
                error: err
            });
        });
});
like image 40
hussam Avatar answered Oct 09 '22 10:10

hussam