Request module: what if server doesn't respond? - node.js

The Node JS request module has a callback containing that fires whenever the response is received, but what if the server doesn't respond?
I will illustrate it with an example.
My code looks like this:
request(TARGET_URL, function (error, response, body) {
if (response.statusCode == 200) doSomething()
})
So, again: what if the server doesn't respond? How can I avoid the program execution to halt if the TARGET_URL server doesn't respond?

In this case a callback function still will be called after some time, but its first argument won't be empty. Quoting the doc:
There are two main types of timeouts: connection timeouts and read
timeouts. A connect timeout occurs if the timeout is hit while your
client is attempting to establish a connection to a remote machine
(corresponding to the connect() call on the socket). A read timeout
occurs any time the server is too slow to send back a part of the
response.
These two situations have widely different implications for what went
wrong with the request, so it's useful to be able to distinguish them.
You can detect timeout errors by checking err.code for an 'ETIMEDOUT'
value. Further, you can detect whether the timeout was a connection
timeout by checking if the err.connect property is set to true.
request.get('http://10.255.255.1', {timeout: 1500}, function(err) {
console.log(err.code === 'ETIMEDOUT');
// Set to `true` if the timeout was a connection timeout, `false` or
// `undefined` otherwise.
console.log(err.connect === true);
process.exit(0);
});
Note that { timeout : 1500 } part: with this approach you can set a specific time for a specific request to be processed.

Related

Wait for socket connection to establish (when changing page path), till sending router data to the user

I need the socket connection to establish before I can send data from the route to the user (otherwise it is not possible).
In app.js file I have socket connection logic:
app.use(function(req, res, next)
{
req.sio = sio;
next();
});
sio.on('connection',
function(soc)
{
console.log('socket connected');
soc.on('disconnect', function(reason)
{
console.log('socket disconnected');
});
// and more about socket connection here...
});
In index.js file I have route.post logic:
router.post('/route1', function(req, res, next) // user is moved from index.js to route1.js if he fills the form
{
var fromInput = req.body.form_name;
console.log('DATA passed from INDEX.JS: ' + formInput);
if ((formInput !== '') && (formInput !== null) && (formInput !== undefined))
{
function render()
{
//// first we render the page, so the javascript (with socket.io notes) can be read it and then the browser know that socket connection should be established
return new Promise(function(resolve, reject)
{
resolve(res.render('route1'));
});
}
// I need to pass some data AFTER the socked connection is established - cause I move to a different page path - using a **router.post** and cause of that socket connection is disconnected - so I need to wait till its usable again. For simplicity let suppose socket connection is established after 2 seconds (it is a simple check for req.soc.connected):
var soc = false;
setTimeout(function()
{
soc = true; // after 2 sec soc is true (connection is established)
}, 2000);
// Now I want to create an interval that will monitor IF socket connection is established every 100ms (so checking won't happen to often - it is not "resource hungry"). If socket connection is not ready the function should call it self (recursion) if the socket connection is established it (function) should fire a promise.
var arr = [];
arr.push(exe(100, data));
function exe(delay, d)
{
d = data;
return new Promise(function(resolve)
{
if (d === false)
{
setTimeout(function()
{
console.log('wait another ' + delay + ' [ms] - ' + d);
return resolve(exe(delay, d));
}, delay);
}
else
{
console.log('socket connected!');
return resolve(d);
}
});
}
render().then(function()
{
return Promise.all(arr).then(function(arr)
{
console.log(arr);
});
}).then(function()
{
console.log('ALL DONE!');
});
}
});
Comment are in code. If something isn't clear let me know.
#jfriend00
1 - true,
2 - true,
3 - I call render() immediately - so page is loaded and client make a socket connection, then the rest of the code should execute and send the data.
yes I did use POST with a form. There could be socket connection between the server and index page - not a problem I can create one, but I dunno what for.
"or there could be a socket.io connection created in the response to the POST when the browser renders and processes that." I'm trying that one :) I have data in this router.post I want to sent with help of sockets - but first I need to make a connection.
as I understand it... user did use form, so path is changed (socket connection is broken), then I'm in router.post I render the page FIRST - so the browser can read it's JS and make a socket connection, BUT you want to say that my response is not finished? So the browser say - ok you want me to render a page, but what now - cause we are NOT finish yet?!
So I will never establish a socket connection, cause I did not properly response? And cause of this I will not be able to send the data (later code in router.post) cause socket connection is never established cause I did not response properly? Cause my tests show me otherwise - it is working just fine.
you are right - code should works now.
till socket connection is established.
yea, good catch. I will make some kind of database - redis with express session I guess.
So again step by step.
User did fill the form so he is redirect from index.js to route1.js (so it does not make a difference if there is a socket connection BEFORE filling the form or not cause the connection is lost). We are in process of redirecting him (router.post) so I thought I will render the route1 page immediately, so the JS from it can be read by browser, and socket connection can be established (which take time - and IF its possible). So I wait with the data I want to sent to the user (in router.post for example... the form input or whatever) TILL the connection is established, and the send it to the user, with help of socket.io.
The thing is that socket io connection is lost when you change page (path). So I thought (and it could be wrong cause I'm newb) then I wait till it is established, and then send the data. I hope it does make sense.
This structure can never work. Here's what it looks like you're trying to do:
Express server receives a POST request.
Then, you try to wait for a socket.io connection to appear before you process the POST and send a response.
Finally, when you think you've found a socket.io connection, you then call your render() function to "presumably" send a response.
Without really understanding what you're' trying to accompilsh, there are a number of things wrong with the current code:
A POST request comes from either an Ajax call or a form POST. There is no socket.io connection associated directly with either one of those. There could have been a socket.io connection when the page loaded BEFORE the POST request was sent or there could be a socket.io connection created in the response to the POST when the browser renders and processes that.
Even if there was a socket.io connection created when the browser processes the POST response, you're trying to wait for the socket.io connection BEFORE you send the response so you're waiting for something that won't happen until you're done waiting (essentially a deadlock - A won't finish until B finishes, but B can't start until A finishes).
This structure render().then(waitUntil(100, d)) isn't correct. You MUST pass .then() a function reference. You are passing it a promise (the return value form calling waitUntil(...)). This is the least of your problems though because the overall structure of what you're trying to do is wrong.
The whole implementation of waitUntil() is confused and I can't even tell what it's trying to actually wait for.
This is a server that can field lots of connections from lots of clients. You can't just wait for the "next" socket.io connection and assume that connection is from the client you just got a request for. The only way to associate a socket.io connection with an http request is to use some identifying characteristic in both (usually a cookie) and then in the http request, you get the cookie and look up the cookie to see if you currently have a socket.io connection that matches that cookie. This is something that express-socket.io-session helps with.
Unfortunately, you don't describe what you're really trying to accomplish here so I can't point you to a good solution. All, I can really say here is that this scheme will not work. If you want further help with the actual problem, please edit your question to include the problem description in words (not your coding issues). Show the exact sequence of events you want to happen and explain what you're trying to accomplish and why.

Request ending early on ExpressJS

router.route('...')
.get(function(req, res, next) {
// This job() function doing some *long* async task and end of the task calling 3th param as callback
job(param1, param2, function(response) {
// printing response to console perfectly
console.log("callback fired", response);
res.send("response");
});
});
And I'm making my request with curl.
$ curl ... -m 300
curl: (52) Empty reply from server
cURL is waiting for a response for a few minutes and then I'm getting empty reply error. cURL is giving this error before nodejs printing callback fired message.
Same error if I make this request with a browser or with Postman.
I'm sure there are no res.send(), res.end() functions inside job() async function. I stuck, how can I track and found the error?
There are two possible timeouts that could be affecting you. Without seeing the actual network trace (to see what happens when the request ends), I can't tell which timeout might be causing your issue. But, you can just address both of them and it should handle your issue.
First, curl has a timeout value. It is unclear what its default setting is, but you can set whatever value you want with:
curl --max-time 900
where the value is in seconds.
Second, the nodejs http server has a timeout where if no response is sent to an open request, it will close the socket (this keeps dead sockets from building up over time). You can see the doc for server.setTimeout() here. The default for the http server object is 2 minutes (I don't know if Express changes that at all).
The general idea is this:
server.setTimeout(10 * 60 * 1000); // set response timeout to 10 minutes
where the server object would be your http server object (not the Express app object).

NodeJs Execute function mutiple times without delay

i will share the code directly
app.get('/ListBooks', function (req, res) {
console.log("Function called");
//internally calls another URL and sends its response to browser
request({
url: 'someURLinRESTServer',
method: 'POST',
json: MyJsonData
}, function (error, response, body) {
if (error) {
console.log("/Call Failed ->" + error);
res.status(200).send('Failed');
} else {
console.log("/Call got Response");
console.log(response.statusCode, body);
res.send(body); res.end();
}
})
now when the browser generates a request on http://localhost/ListBooks
my node console shows the first message "Function called" and waits for internal REST URL Response
the real problem occurs only when the REST SERVER is down
then if i try to call http://localhost/ListBooks from another browser tab the Node server console doesnt show any changes and only after the repsonse of previous function REST CALL call it displays console message of second function call on app.get('/ListBooks'
i thought node js makes async functions bt here i dnt want functions to wait likes this for multiple instance calls
or is it just a delay in printing message and each function call executes separately .Plz clarify ...
If this is only occurring when the REST server is down (as your comment indicates), then that's just a function of how long your calls to request() take to fail. And, each separate call to request() goes through its own cycle of trying to connect and then eventually timing out. If both are timing out, then you will issue request1, then request2, then some timeout amount of time will pass and request1 will fail and then request2 will fail shortly after it. This has nothing to do with how express handles multiple requests and everything to do with how the calls to your REST server behave.
You can set the timeout option for request() if you want to shorten how long it will wait for a response, but you do need to make sure you don't shorten it so much that a busy REST server that just takes a little while to actually respond gets timed out.
or is it just a delay in printing message and each function call
executes separately
Each call is acting completely separately. There is no serialization of these responses by node.js or by Express. The appearance of serialization is just because they both take the same amount of time to fail with a timeout so they will fail one after the other.

Node server, socket, request and response timeouts

Problem
Node's default configuration timeouts requests after 2 minutes. I would like to change the request timeouts to:
1 minute for 'normal' requests
5 minutes for requests that serve static files (big assets in this case)
8 hours for uploads (couple of thousand pictures per request)
Research
Reading through Node's documentation, I've discovered that there are numerous ways of defining timeouts.
server.setTimeout
socket.setTimeout
request.setTimeout
response.setTimeout
I'm using Express which also provides middleware to define timeout's for (specific) routes. I've tried that, without success.
Question
I'm confused about how to properly configure the timeout limit globally and per route. Should I configure all of the above timeouts? How is setting the server's timeout different to setting the socket's or request's timeout?
As I saw on your other question concerning the usage of the timeout middleware, you are using it somehow differently.
See documentation of timeout-connect middleware.
Add your errorHandler-function as an EventListener to the request, as it is an EventEmitter and the middleware causes it to emit the timeout-event:
req.on("timeout", function (evt) {
if (req.timedout) {
if (!res.headersSent) {
res
.status(408)
.send({
success: true,
message: 'Timeout error'
});
}
}
});
This is called outside of the middleware stack, causing the function call to next(err) to be invalid. Also, you have to keep in mind, that if the timeout happens while the request is hanging server-side, you have to prevent your server code from further processing this request (because headers are already sent and its underlying connection will no longer be available).
Summary
nodejs timeout API are all inactivity timeout
expressjs/timeout package is response hard timeout
nodejs timeout API
server.timeout
inactivity/idle timeout
equal to socket timeout
default 2min
server.setTimeout
inactivity/idle timeout
equal to socket timeout
default 2min
have callback
socket.setTimeout
inactivity/idle timeout
callback responsible to end(), destroy() socket
default no timeout
response.setTimeout
socket.setTimeout front end
request.setTimeout
socket.setTimeout front end
expressjs/timeout package
response hard-timeout (vs inactivity)
have callback
Conclusion
max. time allowed for an action(request+response), express/timeout package is needed.
This is properly what you need, but the callback need to end the request/response. As the timeout only trigger the callback, it does not change the state or interfere with the connection. It is the callback job.
idle timeout, set nodejs api request/response timeout
I don't recommend touching these, as it is not necessary in most cases. Unless you want to allow a connection to idle(no traffic) over 2min.
There is already a Connect Middleware for Timeout support. You can try this middleware.
var timeout = express.timeout // express v3 and below
var timeout = require('connect-timeout'); //express v4
app.use(timeout(120000)); // should be changed with your desire time
app.use(haltOnTimedout);
function haltOnTimedout(req, res, next){
if (!req.timedout) next();
}

node.js wait for response

I have a very limited knowledge about node and nob-blocking IO so forgive me if my question is too naive.
In order to return needed information in response body, I need to
Make a call to 3rd party API
Wait for response
Add some modifications and return JSON response with the information I got from API.
My question is.. how can I wait for response? Or is it possible to send the information to the client only when I received response from API (as far as I know, connection should be bidirectional in this case which means I won't be able to do so using HTTP).
And yet another question. If one request waits for response from API, does this mean than other users will be forced to wait too (since node is single-threaded) until I increase numbers of threads/processes from 1 to N?
You pass a callback to the function which calls the service. If the service is a database, for example:
db.connect(host, callback);
And somewhere else in the code:
var callback = function(err, dbObject) {
// The connection was made, it's safe to handle the code here
console.log(dbObject.status);
res.json(jsonObject, 200)
};
Or you can use anonymous functions, so:
db.connect(host, function(err, dbObject) {
// The connection was made, it's safe to handle the code here
console.log(dbObject.status);
res.json(jsonObject, 200)
});
Between the call and the callback, node handles other clients / connections freely, "non-blocking".
This type of situation is exactly what node was designed to solve. Once you receive the request from your client, you can make a http request, which should take a callback parameter. This will call your callback function when the request is done, but node can do other work (including serving other clients) while you are waiting for the response. Once the request is done, you can have your code return the response to the client that is still waiting.
The amount of memory and CPU used by the node process will increase as additional clients connect to it, but only one process is needed to handle many simultaneous clients.
Node focuses on doing slow I/O asynchronously, so that the application code can start a task, and then have code start executing again after the I/O has completed.
An typical example might make it clear. We make a call to the FB API. When we get a response, we modify it and then send JSON to the user.
var express = require('express');
var fb = require('facebook-js');
app.get('/user', function(req, res){
fb.apiCall('GET', '/me/', {access_token: access_token}, function(error, response, body){ // access FB API
// when FB responds this part of the code will execute
if (error){
throw new Error('Error getting user information');
}
body.platform = 'Facebook' // modify the Facebook response, available as JSON in body
res.json(body); // send the response to client
});
});

Resources