I have a node.js service that is being called from a main application. I've had issues where an error occurs in the service and the service hangs preventing any other requests from being handled. I have code to catch errors in common places like after doing a mongodb query.
model.aggregate(
[
...
],function (err, result) {
if (err) {
next(err);
}
else {
//other code
}
I am also catching uncaught exceptions and killing the service in this case with the following code.
process.on('uncaughtException', function (er) {
console.error(er.stack);
logger.log('info','Cbt Dev Service crashed',er);
process.exit(1);
});
These seem to be working fine except I occasionally run into issues where an error occurs but isn't caught by either. An exmple of an error in this case is after getting a result from a mongodb query and getting an error like "Cannot read property 'subjectAreas' of undefined. This error seems to get caught by the mongodb middleware. The code looks like this.
function (err, result) {
if (err) {
res.send(errorHandler(err, req));
}
else {
var subjectAreas = result[0].subjectAreas.sort();
}
In this case result is an empty array so obviously throws an error. I understand that I can prevent this with better written code like using try/catch but if I'm not aware this issue exists and the service hangs up again, I don't know what the error is in order to fix it so that's why I need to log it.
Is there something else I can do that will catch these kinds of errors?
Related
I am very aware of the problems with using uncaughtException in my code. I am also aware that the domains module is being deprecated so I do not want to use that. My question is what to do when I encounter an error that should not happen. For instance, if using mongo db and mongoose the following code example is give:
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('meow');
}
});
Here there is, what I assume is an inexplicable error. It is caught, but only uses console.log to log the error. Clearly more would have to happen to inform the user there is a problem, but I am wondering what should happen to the rest of the application.
Should it shutdown? Should something else happen? I have a good number of cases where I can catch errors like this, but if they happen they represent some very weird situation where something like the database has failed, or something else from another library has failed for no explicable reason and
I suggest you to return a json to your app showing the results of operation. Example:
if(err) {
res.status(500).json({saved: false, errormsg: 'Cannot save to database'});
} else {
res.json({saved: true, errormsg: null});
}
Handle the response in your app and show to the user that some bad think happened.
When an error occurs in NodeJS application, the server may crash and stop if an exception occurs.
How can I prevent this situation so that the server never stops on error, but returns and error code instead ?
--
EDIT
Here is a method which causes a server crash (table foo doesn't exist) :
app.get('/articles/list', function(req, res) {
connection.query('select * from foo', function(err, rows, fields) {
if (err) throw err;
res.send(JSON.stringify(rows));
});
});
-- BEST SOLUTION
Finally, I found the best solution for me :
http://rowanmanning.com/posts/node-cluster-and-express/
In summary, it consists in using a cluster of server, and to restart a server when it exits
If you are using express, you can use this
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
app.use(clientErrorHandler);
I suggest you to ready this article, it will clarify a lot for you.
JFK, be aware of async error catching, most common error, once you have async stuff which is wrapped in try-catch.
Also, avoid usage of
process.on("uncaughException", () => {....})
This is quite bad, because when an uncaught exception is thrown you can’t reliably continue your program at this point.Let it fail and restart with daemonizer's like pm2, forever and etc.
As general rule, you should handle all errors and promise rejects in your code to avoid uncaught Exceptions.
For errors: using try-catch statement
For promises: using .catch method
Btw Node permits you to intercept an uncaughtExceptions or unhandledRejection events, but is not a good practice to handle errors at this level and prevent program exits, because can generate unpredictable behaviours.
Use try catch... for parts of code, which throws exception
try{
//youre code here
}catch(error){
console.log(error)
}
I am creating an application in SailsJS. I am getting errors, like, typeError or 500 errors when some error occurs in DB related queries.I am using MongoDB. Is there any way that I can catch this error in server-side.
Now, these errors are crashing my server. And the server stops. I have to restart the server again.
Please help me in fixing this issue.
Thanks in advance.
Most likely waterline is throwing an exception and you're not catching it. Here's some code to fix that:
controlleAction:function(req,res){
var invalidParams = {};//whatever's causing the error
Model
.create(invalidParams)
.exec(function(err,created){
if(err) res.json(err);
res.json(created);
});
}
you could also use the promise syntax
controlleAction:function(req,res){
var invalidParams = {};//whatever's causing the error
Model
.create(invalidParams)
.then(function(created){
res.json(created);
})
.catch(function(err){
res.json(err);
});
}
If you're trying to catch every global error in your entire application,
in your app.js, there's a line like this:
// Start server
sails.lift(rc('sails'));
surround that line with a try catch block like so:
try{
// Start server
sails.lift(rc('sails'));
}catch(e){
console.dir(e);
}
Please be careful there:
controlleAction:function(req,res){
var invalidParams = {};//whatever's causing the error
Model
.create(invalidParams)
.exec(function(err,created){
// return res.json()
if(err) return res.json(err);
return res.json(created);
});
}
// The difference is in the return
if(err) return res.json(err);
If you have an error, without the return, the server will crash because it would try to send two responses one with the error and another one with the created object.
If you are using Sails 0.10.x you can pass errors to next handler:
controlleAction:function(req,res, next){
var invalidParams = {};//whatever's causing the error
Model
.create(invalidParams)
.exec(function(err,created){
if(err) return next(err);
return res.json(created);
});
}
And then process errors in "Custom Responses"
I am running node.js with express. I wrote a node module with methods in it so when you go to
http://bla.com/module_name/method_name
it will run the method.
The method follows the typical style of
exports.method_name(req, res, next);
my main app does something like this:
app.all("*", resSetup, controller, render);
and controller is the thing that will call the method based on the path.
it seems that if there is an undefined variable error in the method, express will just hang there and not throw any error. Nothing will appear in the console log either. I can put a console message right before and after where the error occurs and the before will appear in the log, and after will not.
I can wrap it in a try/catch and get this:
[ReferenceError: blabla is not defined]
but no line numbers or anything.
My guess is that express is somehow preventing the errors from coming up. When I put the error in the function called "controller" that is directly in the route, it shows that error correctly.
It might not matter too much, but here is the code I am working on:
https://github.com/RobKohr/quick-site/blob/master/index.js
Line 189 is where the method call happens.
Building on Ruairi's comment above, I had this same issue with when using 'q' (https://github.com/kriskowal/q) and promises with express - node would hang and no error was generated.
By adding a catch to the end of the promise 'callback' chain I was able to see the error and print it to console etc.
The code ends up looking like:
export function index(req, res) {
//Create the 'promise'
var request = req.body;
var queryJobID = req.query.jobId;
console.log('queryJobID: ' + queryJobID);
var jobStatusPromsie = jobManager.job.getStatus(queryJobID);
Q.all([jobStatusPromsie])
.then(
function (result) {
var responseData = {};
console.log('Job Status Response received');
if (result != null) {
//Without the .catch below an error here will be 'silent'
console.log('jobStatus result: ' + util.inspect(result, false, null));
responseData['status'] = 'OK';
responseData['progress'] = result.progress;
res.json(responseData);
} else {
console.log('jobStatus Error');
responseData['status'] = 'Error';
}
res.json(responseData);
console.log('jobStatus Response data sent');
},
function (error) {
console.log('Error while getting job status:', error);
res.json("Error");
})
.catch(function(err) {
//handle errors
console.log('Promise error while getting job status:', err);
});
}
Express heavily relies on Nodes asynchronous nature. Seeing errors thrown like on line 30 would give me the creeps if I was maintaining this. Try refactoring your code to only use the next(err) pattern.
The reason that you app is hanging is that Express hasn't finished the HTTP response (eg: res.send()). This means you have broken plumbing where an Error has bubbled up the call stack but not redirected into the Express middleware pipeline. Try registering some error middleware to see if it gets called with your error.
I have a Node.js (v5.6.0, npm: v3.7.1) app running with Sails.js (v0.12.0).
When I execute this code in app.js:
process.on('uncaughtException', err => {
//Do something
});
throw new Error();
It handles my error.
The problem is, after I load Sails, I can't catch errors with this method at all.
For example, throwing an error from bootstrap.js will not be caught by the above code and I get this message in my console:
error: Bootstrap encountered an error: (see below)
error: Error: asdf
at Object.module.exports.bootstrap.process.on.process.on.process.on.sails.async.series.callback [as bootstrap]
(c:\path\to\project\config\bootstrap
.js:41:8)
at Sails.runBootstrap (c:\path\to\project\node_modules\sails\lib\app\private\bootstrap.js:44:25)
at Sails.wrapper [as runBootstrap] (c:\path\to\project\node_modules\sails\node_modules\lodash\index.js:3095:19)
at Sails.initialize (c:\path\to\project\node_modules\sails\lib\app\private\initialize.js:54:9)
at wrapper (c:\path\to\project\node_modules\sails\node_modules\lodash\index.js:3095:19)
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:713:13
at iterate (c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:262:13)
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:274:29
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:44:16
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:718:17
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:167:37
at module.exports (c:\path\to\project\node_modules\sails\lib\app\load.js:184:13)
at _toString (c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:52:16)
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:548:17
at c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:542:17
at _arrayEach (c:\path\to\project\node_modules\sails\node_modules\async\lib\async.js:85:13) [Error: asdf]
I also tried to move the above code in bootstrap.js without any luck.
How can I handle any error with Sails project?
Thanks in advance!
For whom will come here and looks for full code, I'm posting my full code and explanation, based on #sgress454 answer:
Sails is a Web Framework that wraps your code to a web application, so it can't be never down, therefore-Sails try to handle all the errors by itself, and notify the user with 500 if needed, and continue to run the web application.
Sails app is divided into 2 steps:
Before Lifting-The web application isn't accessible by anyone:
If Sails got exception, it will quit the app, and call the lift callback with an error argument.
After Lifting-The web application is accessible:
If Sails got exception, it will quit the app, and call the lift callback with an error argument.
If Sails got exception while running the web application(after lifting), there's 2 options:
Exception inside a controller action itself:
Sails will catch this error, and respond to the user with 500.
Exception wherever else:
Sails wouldn't catch this error, and an uncaughtException will be thrown.
To handle all the above case we need to do the following:
First we want to create a global function so we can call it from wherever we are in the code:
ES 2015:
//app.js
global.handleErrors = err => {
//do something
}
ES 5.1(and before):
//app.js
global.handleErrors = function(err) {
//do something
}
Now we want to handle all uncaughtException's events:
//app.js
process.on('uncaughtException', handleErrors);
We can add some other events ex.:
//app.js
process.on('unhandledRejection', handleErrors);
process.on('rejectionHandled', handleErrors);
process.on('SIGINT', handleErrors);
To catch exceptions that happens in the lifting process we need to provide a callback to sails.lift function, and if the callback is called with an error we need to call the handleErrors function that we created:
ES 2015:
//app.js
sails.lift(rc('sails'), err => {
if (err) {
handleErrors(err);
}
});
ES 5.1(and before):
//app.js
sails.lift(rc('sails'), function(err) {
if (err) {
handleErrors(err);
}
});
And we want to handle exceptions in controllers that Sails catches and responded with 500:
//api/responses/serverError.js
module.exports = function serverError(data, options) {
handleErrors(data);
//lot of Sails things
};
In this way all the errors eventually will be hit the handleErrors function, so we can do there whatever we want with the error, ex. log to file, log to log management tool, send email to admin etc.
The code you posted will do exactly what it says: handle uncaught exceptions. Sails handles errors that occur during its initialization so it can attempt to exit gracefully, and attempts to handler errors that occur when processing requests so it can respond gracefully (with an error page) instead of crashing the server.
To handle errors that occur during the initialization process, provide a second argument--an error handling function--to .lift() in your app.js file:
sails.lift(rc('sails'), function handleLiftError(err, sailsInstance) {
if (err) {
console.log("Error occurred during sails.lift: ", err);
}
});
You can still leave your process.on('uncaughtException'),... code in to handle fatal errors that pop up as the app is running. For instance, if you had the following in a controller action:
myAction: function (req, res) {
throw new Error('foo!);
}
then Sails would catch that error for you and just respond with the 500 error page. But if you had:
myAction: function (req, res) {
setTimeout(function(){throw new Error('foo!);}
}
Sails would not catch it at all--but your process.on handler would (provided you started Sails with node app.js!)