What I Have: I have a nodejs express server get endpoint that in turn calls other APIs that are time consuming(say about 2 seconds). I have called this function with a callback such that the res.send is triggered as a part of the call back. The res.send object packs an object that will be created after the results from these time consuming API calls is performed. So my res.send can only be sent when I have the entire information from the API call.
Some representative code.
someFunctionCall(params, callback)
{
// do some asyncronous requests.
Promise.all([requestAsync1(params),requestAsync2(params)]).then
{
// do some operations
callback(response) // callback given with some data from the promise
}
}
app.get('/',function(req, res){
someFunctionCall(params, function(err, data){
res.send(JSON.stringify(data))
}
}
What I want I want my server to be able to handle other parallel incoming get requests without being blocked due to the REST api calls in the other function. But the problem is that the callback will only be issued when the promises are fulfilled,each of those operations are async, but my thread will wait till the execution of all of them. And Node does not accept the next get request without executing the res.send or the res.end of the previous request. This becomes an issues when I have multiple requests coming in, each one is executed one after another.
Note: I do not want to go with the cluster method, I just want to know if it is possible to this without it.
Express. js use different kinds of middleware functions in order to complete the different requests made by the client for e.g. client can make get, put, post, and delete requests these requests can easily handle by these middleware functions.
How NodeJS handle multiple client requests? NodeJS receives multiple client requests and places them into EventQueue. NodeJS is built with the concept of event-driven architecture. NodeJS has its own EventLoop which is an infinite loop that receives requests and processes them.
As is, node. js can process upwards of 1000 requests per second and speed limited only to the speed of your network card. Note that it's 1000 requests per second not clients connected simultaneously. It can handle the 10000 simultaneous clients without issue.
There's a benchmark made by Fastify creators, it shows that express. js can handle ~15K requests per second, and the vanilla HTTP module can handle 70K rps.
You are apparently misunderstanding how node.js, asynchronous operations and promises work. Assuming your long running asynchronous operations are all properly written with asynchronous I/O, then neither your requestAsync1(params)
or requestAsync2(params)
calls are blocking. That means that while you are waiting for Promise.all()
to call its .then()
handler to signify that both of those asynchronous operations are complete, node.js is perfectly free to run any other events or incoming requests. Promises themselves do not block, so the node.js event system is free to process other events. So, you either don't have a blocking problem at all or if you actually do, it is not caused by what you asked about here.
To see if your code is actually blocking or not, you can temporarily add a simple timer that outputs to the console like this:
let startTime;
setInterval(function() {
if (!startTime) {
startTime = Date.now();
}
console.log((Date.now() - startTime) / 1000);
}, 100)
This will output a simple relative timestamp every 100ms when the event loop is not blocked. You would obviously not leave this in your code for production code, but it can be useful to show you when/if your event loop is blocked.
I do see an odd syntax issue in the code you included in your question. This code:
someFunctionCall(params, callback)
{
// do some asyncronous requests.
Promise.all([requestAsync1(params),requestAsync2(params)]).then
{
// do some operations
callback(response) // callback given with some data from the promise
}
}
should be expressed like this:
someFunctionCall(params, callback)
{
// do some asyncronous requests.
Promise.all([requestAsync1(params),requestAsync2(params)]).then(function(response)
{
// do some operations
callback(response) // callback given with some data from the promise
}
});
But, an even better design would be to just return the promise and not switch back to a plain callback. Besides allowing the caller to use the more flexible promises scheme, you are also "eating" errors that may occur in either or your async operations. It's suggest this:
someFunctionCall(params) {
// do some asyncronous requests.
return Promise.all([requestAsync1(params),requestAsync2(params)]).then(function(results) {
// further processing of results
// return final resolved value of the promise
return someValue;
});
}
Then, then caller would use this like:
someFunctionCall(params).then(function(result) {
// process final result here
}).catch(function(err) {
// handle error here
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With