Promise reject paused with an exception yet no error is log - javascript

Below is a Nodejs piece of code. I'm querying a Mongodb using mongoose. This piece of code gets paused at "Line A" with message "Paused on Exception". console shows no errors. Meanwhile this seem to happen only when I run in VS Code. Running the app from console raises no exception.
I'm inclined to say this a VS Code issue. Has anyone seen/faced same or something similar?
Board.findOne({ boardId: id }, function (err, data) {
if (!err) {
data ? resolve(data.children) : reject(data); //Line A
// line above pauses execution with this message: "Paused on Exception"
// No error logged in console. And this seem to happen only in VS code.
}else{
reject(err);
}
}

Mongoose already supports promises, so you can rewrite your code to this:
return Board.findOne({ boardId: id }).then(function(data) {
if (! data) throw new Error('data empty');
return data.children;
}).catch(function(err) {
console.log(err);
});
Perhaps this also solves your VS Code issue.

Related

How to catch unhandledRejection?

I wrote a Telegram bot using TelegrafJS, this framework wraps the Telegram API. The problem that I'm facing is how to correctly manage the unhandled rejection, in fact when I call this method:
await ctx.deleteMessage(message_id);
where ctx is the instance of TelegrafJS I got:
Bot error: Error: 400: Bad Request: message to delete not found
this error happens 'cause the message_id that I passed no longer exists in Telegram chat. Now, the problem is that I have several controllers which can cause that problem.
I was looking at Promise.prototype.catch(), my question is: can I set up a global rejection handler for my application, or should I use a try/catch block to methods potentially subject to exceptions?
Yes you can, and it is pretty simple:
process.on('unhandledRejection', (err) => {
//handle it!
});
You can also catch the unhandled exceptions, using the same code basically:
process.on('uncaughtException', (err) => {
//handle it!
});
test this code:
bot.use((ctx, next) => {
try {
...
} catch(error) {
next();
}
})
For error handler, you can use:
bot.catch((err, ctx) => {
console.log(err);
return ctx.reply("Error Message");
});

Error from nodejs server thrown not being passed back to AJAX

I have the following AJAX that will send the entered data to the node server and the controller will check whether such data exist in the database or not.
If I do enter the data correctly, then everything is working fine.
However, I tried enter anything that the database does not have and it immediately throw an error, causing the server to stop. The error said that I did not handle the event, so I tried with res.json(err) in the controller instead of throw new Error, hoping that the error will be passed back to AJAX under the error key, but it is still not working. The error still gets thrown and the node server terminate itself.
I would like the server to continue and alert to the user that the data that was entered is not in the database but I have no idea why my approach is not correct.
I was thinking of using this SO thread if I'm able to get the error message back first from server side.
jQuery Ajax error handling, show custom exception messages
To solve the server from stopping, I used the code in app.js that was referred from this link
How do I prevent node.js from crashing? try-catch doesn't work
I'm not sure whether should I use the accepted answer for my case.
function createProduct(inputval){
let inputAction = window.location.pathname;
$.ajax({
type: "POST",
url: inputAction,
data: {order: inputval.split('-')[0].trim(), lot: inputval.split('-')[1].substring(0,5)},
success: function(data) {
$('#product').val('');
//Another function to add HTML
display(data);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("XHR" + jqXHR)
console.log("Status" + textStatus)
console.log(errorThrown)
}
});
}
Controller File
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (!product || err){
throw new Error("The product entered returns null");
}
res.json(product);
});
};
Main File: app.js
process.on('uncaughtException', function (err) {
console.error(err);
console.log("Node NOT Exiting...");
});
You should use correct status code for your response. I suggest change your controller like below snippet
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (err){
res.status(500).end();//means internal server error
} else if (!product) {
res.status(404).end();//means product not found
} else {
res.json(product);
}
});
};
I finally figure it out thanks to feedback from other community, so I thought I would just share it here. It's so simple and silly me for neglecting such statement.
First, the code in app.js can just be removed.
Second, based on the answer given by #Milad Aghamohammadi. Instead of just:
res.status(500).end();
Use:
return res.status(500).json({err: "Server error"});
This way, the error is able to be handled by the AJAX error function and the node server will not be terminated from the event loop.

Node: Wait for python script to run

I have the following code. Where i upload the file first and then i read the file and console the output like console.log(obj). But the response comes first and the python scripts runs behind the scene. How can i make code to wait for the python script to run then proceed?
router.post(`${basePath}/file`, (req, res) => {
//Upload file first
PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
console.log(err);
let obj = fs.readFileSync('Path/to/file', 'utf8');
console.log(obj);
});
return res.status(200).send({
message : 'Success',
});
});
I cannot get console.log(obj); output because it runs after the response. How can i make it wait for the python script to run and get console.log(obj) output on console.
To return the result after some async operation, you should call res.send inside the done-callback.
router.post(`${basePath}/file`, (req, res) => {
//Upload file first
PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
console.log('The script work has been finished.'); // (*)
if(err) {
res.status(500).send({
error: err,
});
console.log(err);
return;
}
let obj = fs.readFileSync('Path/to/file', 'utf8');
console.log(obj); // (**)
res.status(200).send({
message : 'Success',
});
});
});
Then if you will not see the log (*) in the console, then it would mean that the script does not work or works improperly. The callback is not being called. First of all, you need to be sure that the script (PythonShell.run) works and the callback is being called. The POST handler will wait until you call res.send (with no matter of delay value), so that callback is the main point.
Also readFileSync could fail. In case of readFileSync failure you should see an exception. If it's ok then you'll see the next log (**) and the response will be sent.
I see PythonShell in your code. I have no experience with it, but after some reading I think that the problem could be in how you are using it. It seems the python-shell npm package, so following it's documentation you may try to to instantiate a python shell for your script and then to use listeners:
let pyshell = new PythonShell('calculations.py');
router.post(`${basePath}/file`, (req, res) => {
pyshell.send(settings); // path, args etc
pyshell.end(function (err) {
console.log('The script work has been finished.');
if(err) { res.status(200).send({ error: err }); }
else { res.status(200).send({ message : 'Success' }); }
});
});
This approach could be more appropriate because the pyton shell is kept open between different POST requests. This depends on your needs. But I guess it does not solve the problem of script running. If you are sure that the script itself is fine, then you need just to run it properly in the Node environment. There are some points:
path to script
arguments
other settings
Try to remove all arguments (create some new test script), cleanup settings object (keep only path) and execute it from Node. Handle its result in Node. You should be able to run the simplest script by correct path! Research how to setup correct scriptPath. Then add an argument to your script and run it with an argument. Hanlde the result again. There are not so many options, but each of them could be the cause of improper call.

reporting errors when using async with streams node.js

I am having problems trying to report errors from a function where I read a file and pipe it through csv-parse. What I want to do, is if there is a line that does not have three fields, I want to report back an error - to an async.series call. This first implementation fails as
function insertCsvIntoObject(done) {
fs.createReadStream(inputCsvFilepath)
.pipe(csvParser)
.on('data', function (csvRow) {
console.log('csv row:', csvRow);
if (csvRow.length !== 3) {
this.emit('error', "Does this go anywhere?");
}
})
.on('end', function () {
done(null, "Finished reading through the csv data");
})
.on('error', function (err) {
console.log('errors is now:', csvReadErrors);
done(new Error('Error reading csv file'), "CSV Parse error");
});
}
This gives a
Exception: [Error: Callback was already called.] if we have multiple problematic rows in the csv file.
Adding a return before the done
return done(new Error('Error reading csv file'), "CSV Parse error");
is also no help, since we cannot stop and return from the parent function - insertCsvIntoObject.
furthermore, if there are any error events, the .on('end',..) event never gets fired.
What is the correct way to report errors in such a situation?
It looks like csv-parse already emits an error when the number of columns on a line isn't consistent. In other words, you shouldn't have to emit one yourself.
To prevent a callback from being called multiple times, you can use a packaged like once:
function insertCsvIntoObject(done) {
done = once(done);
...
};
Ideally, you should be able to end the processing after the first error, but I haven't been able to stop the parser from parsing additional records (this.end() doesn't seem to work, but perhaps I'm missing something).

how to prevent node.js application from terminated for unhandled exception in setInterval?

Node.js application terminated for unhanded exception in setInterval. I try to fix it by process.on('uncaughtException', ..) and domain approaches (see below codes). Application still was terminated although the exception was handled.
function f () {
throw Error('have error')
}
process.on('uncaughtException', function(err){
console.log("process.on uncaughtException")
})
var d = require('domain').create();
d.on('error',function(err){
console.log("domain.on error")
})
d.run(function(){
setInterval(f, 1000)
})
// program terminated and output is: domain.on error
Program terminated because there was nothing else to process after setInterval(). In nodejs doc example, it creates the the server and bind the port to it. That's what keeps the application running. Here is the example from the doc:
var d = require('domain').create();
d.on('error', function(er) {
// The error won't crash the process, but what it does is worse!
// Though we've prevented abrupt process restarting, we are leaking
// resources like crazy if this ever happens.
// This is no better than process.on('uncaughtException')!
console.log('error, but oh well', er.message);
});
d.run(function() {
require('http').createServer(function(req, res) {
setInterval(f, 1000);
}).listen(8888);
});
Then if you point your browser to localhost:8888, the app is not terminated

Categories