I can't understand why my ExpressJs app is crashing sending res.status(401) inside a middleware.
Let's say my start.js has:
app.use(middlewares.timestampValidator());
and the middleware is declared as follow:
timestampValidator: () => {
return (req, res, next) => {
[...]
if(error) {
res.status(401).json(new ServerResponse());
}
else {
next();
}
}
}
When the error is -successfully- sent to the client the server crashes with this error:
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async > function without a catch block, or by rejecting a promise which was not handled with > > .catch(). The promise rejected with the reason "false".] {
code: 'ERR_UNHANDLED_REJECTION'
}
But the functions is not async.
I tried calling next('error'); after sending status 401 but the app continues to routes and then the response can't be send to client because already sent.
I got the same thing in my nodejs application. My middleware was crashing in the application, and after some time of the crash, the unhandlesPromiseRejectionException was raised. The middleware is not async, but this crash is stopping the execution of the code (if try catch is not used to handle it), thereby terminating the entire process and then after a while the exception is raised.
If you notice the time of error receiving on the client, you could see that you get the error on the client sooner and the PromiseException gets raised later. I would ask you to check, if the error you get on the client, is that a timeout error, or the error code that you have thrown
I think Express just raises unhandled exception in middlewares as unhandledPromiseRejection By default as it is a break in its api hittin process which is asynchronous by default. EVen though your middleware is synchronous, but it is placed in an asynchronous process of an API route, and if anything crashes in it which is not handled, it will raise an UnhandledPromiseRejectionException as it is a crash in an asynchronous process.
Try to think of it as this : -
public async randomeFUnction()
{
syncFUnction1()
syncFUnction2()
await asyncFUnction()
}
now if syncFunction1 crashes, it will still be an unhandledPromiseException, although the main stacktrace leads to a sunchronous method, but essentially, randomeFUnction is the one which has failed, which is an async function.
I would suggest to use try catch to prevent a formal crash rather than an If condition.
Let me know if it helps.
Related
I'm making a backend server with Node.js (based on Nest.js). Each route handler mainly queries/modifies the database (main effect), and sometimes send events to external server, leave log and etc (side effect).
I want each route handler functions not to fail when only side effect throws error and main effect goes well(behavior 1). And I also want the side effects to be executed in parallel with the main effect so that the time executing each route handler functions can be decreased(behavior 2).
How can I achieve this behavior in javascript? I first tried this code:
async routeHandler() {
sideEffect().catch(console.error)
await mainEffect();
}
However, when the sideEffect function throws an error, the routeHandler function fails. I can try next, but it does not satisfies the behavior 2.
async routeHandler() {
try {
await sideEffect();
} catch (error) {
console.error(error);
}
await mainEffect();
}
maybe what you are looking to use is Promise.allSettled?
Run async tasks in parallel
the other async tasks should still continue even if the other tasks has been rejected
Link for the docs: check the compatibility section as well.
Is there any caveats in sending response before resolving promises in express?
For instance, is it OK to do this:
app.get('/', async (req, res) => {
res.send('Response sent before other stuff!');
await something();
await somethingElse();
});
Will I have some hard-to-debug bugs?
You've said you're not sending more data later. If that's the case, I'd probably call end to let Express know the response is complete, but I don't think Express cares what your function does after that. Express doesn't expect the lifetime of the call to the function and the lifetime of building the response to match (they almost never do, usually the function just starts a process and the response is filled in by callbacks).
Aside from that, though, if you're going to pass an async function into app.get (or anything else that doesn't handle the promise async functions return), be sure to wrap all of your code in a try/catch and handle the errors, since the thing you're returning the promise to won't handle promise rejections.
So for instance:
app.get('/', async (req, res) => {
// Part 1: The code that handles producing the response
try {
// ...presumably some code here that may fail...
res.send('Response sent before other stuff!').end();
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^
} catch (e) {
// ...send appropriate error response...
// Return so the other code doesn't run
return;
}
// Part 2: The code after the response
try {
await something();
await somethingElse();
} catch (e) {
// ...handle and/or log the error, etc...
}
});
Note the two different blocks there, one for errors that may affect the response, one for errors that don't.
(You'd probably want to abstract this pattern into a function rather than rewriting it every time.)
Im using the async function inside the object to send a response in express.js
Controller Code :
module.exports = {
async signUpEmail(req, res) {
/**
* #description Parameters from body
* #param {string} firstName - First Name
* #inner
*/
const firstName = req.body.firstName;
res.send({ success: name });
throw new Error(); // purposely Done
}
}
Question:
Since the signUpEmail method is async in my case and it will get rejected with whatever my async method throw's here it's comes Error.(purposely put there)
so getting this logged in the console.
(node:13537) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error
(node:13537) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
So i'm supposed to handle it from the routes from where i'm calling it.
Router Code
const routes = require('express').Router();
const SignUpController = require('../controllers/signUpController')
// /signup
routes.post('/', SignUpController.signUpEmail);
module.exports = routes;
some what like this SignUpController.signUpEmail().then(…); But since i'm not calling function in the routes i'm just passing. How this can be done effectively ?
PS:Please Don't suggest too complicated solutions. I'm beginner with JS and is learning through.
I Didn't use chainable route handlers because i want to create modular, mountable route handler.
Official Doc Example
In your route, you will need to add a wrapper to catch thrown errors:
let wrapper = fn => (...args) => fn(...args).catch(args[2]);
// /signup
routes.post('/', wrapper(SignUpController.signUpEmail));
With this method you can use a top level error catcher and do not need to use internal try catch blocks in your routes, unless you need to them contextually.
Use error catching middleware to achieve this as follows:
// last middleware in chain
app.use(function(err, req, res, next) {
// handle your errors
});
Now in your routes you can throw errors and they will be caught by that middleware. I like to throw custom errors and handle their response and logging in this middleware.
Aside: The async await pattern is great for writing asynchronous code that is easy for a human to read in a synchronous fashion. Just remember that once you go async, you should stay async! Using a promisification library such as Bluebird and invoking .promisifyAll on nodeback libraries is highly recommended.
EDIT : Source - Asynchronous Error Handling in Express with Promises, Generators and ES7
In one of my app's route handlers, I am calling a method that returns a Q promise. Rather than handling the rejection using the .catch method, I want it to be thrown and get caught by my Express app's catch-all error handler.
I tried Q's done method, but it throws the exception asynchronously, so rather than it getting handled by my catch-all error handler, it gets propagated all the way up and my app gets terminated:
// The route handler
function index(req, res) {
dao.findById(id).then(function (data) {
res.send(data);
}).done();
}
// The catch all event-handler
function catchAllErrorHandler(err, req, res, next) {
console.log(err, req, res);
}
// Registration of the catch-all event handler
app.use(catchAllErrorHandler);
The error never enters the catch all error handler. Is there a way to make the thrown errors get handled by catchAllErrorHandler?
This does not answer your question directly, but rather shows another way to achieve your goal.
Every middleware handler in express has the signature (request, response, next). Currently your index function does not have next defined.
When calling next with an argument, express considers that argument to be an error, and manages it appropriately.
So, in your case, change your index function to include the next parameter, and change .done() to .catch(next) which will call next with any error that occurs, and allow express to handle it.
dao.findById(id)
// Handle success
.then(function (data) {
res.send(data);
})
// Handle failure
.catch(next);
I tried Q's done method
That's probably the best you get to throw exceptions from promises.
but it throws the exception asynchronously
Of course it does, promises are always asynchronous. You cannot determine whether your promise will reject in the future and synchronously throw an exception…
Is there a way to make the thrown errors get handled by catchAllErrorHandler?
Pass the handler explicitly as a handler:
dao.findById(id).then(function (data) {
res.send(data);
}).catch(catchAllErrorHandler);
Alternatively, since Q v1.3 you can used the unhandled rejection tracking and put your catchAllErrorHandler there.
I am using Bluebird promise. This isn't really explicit in the documentation. Suppose the following, assuming all the instances are appropriate promises:
FindSomeDBModel.then(function(model) {
return [
model.getOtherModels(),
aHTTPRequest('https://google.com')
];
}).spread(function(otherModels, httpResponse) {
// some code
}).catch(function(err) {
res.status(500).send(err);
});
If both model.getOtherModels and aHTTPRequest throws an error, what will be inside the err variable in the catch?
Also, what if model.getOtherModels throws an error first, will it cause a response to be sent out to the client or will it wait for aHTTPRequest to complete? Subsequently, aHTTPRequest throws, then what happens?
Can I respond back to the client as soon as one of the request throws an error? Because it is no longer material whether the other response completes and succeeds.
If an error occurs in one of those two promise executions, what will happen is
the error is received in your catch callback
the other promise is unaffected, its execution goes on
the callback you gave to spread isn't called
If both model.getOtherModels and aHTTPRequest throw an error, only the first one will be received by catch, the other one will just be ignored.
The callback you gave to catch is called as soon as possible, when the first error is thrown, your code doesn't wait for the execution of the other one.
If both model.getOtherModels and aHTTPRequest throws an error, what will be inside the err variable in the catch?
An AggregateError would have been optimal but because of compatibility with .all which is specified outside of Bluebird and bluebird is compatibly with - it'll resolve with the first rejection up the chain.
In its own methods that don't need ES6 compatibility bluebird will return all the errors.
Also, what if model.getOtherModels throws an error first, will it cause a response to be sent out to the client or will it wait for aHTTPRequest to complete? Subsequently, aHTTPRequest throws, then what happens?
It'll reject (and immediately enter the catch) as soon as the error is thrown, bluebird has a special case with .spread which checks if the argument passed is an array and calls .all on it - this is a special case, if you .thend it instead of .spreading it that would not have happened.
Can I respond back to the client as soon as one of the request throws an error? Because it is no longer material whether the other response completes and succeeds.
Yes, but consider using typed (or predicate) exceptions to have more meaningful error handling - if an error that's not an OperationalError happened you might want to restart the server.