There is a post: How do I set a timeout for client http connections in node.js
but none of the answer will work.
So, I have the code like that:
var remote_client = http.createClient(myPost, myHost);
var path = '/getData?';
var param = { };
var request = remote_client.request("POST", path,);
// error case
remote_client.addListener('error', function(connectionException){
console.log("Nucleus Error: " + connectionException);
next(connectionException);
});
request.addListener('response', function (response) {
response.setEncoding('utf-8');
var body = '';
response.addListener('data', function (chunk) {
// get the result!
});
});
request.end();
The biggest problem is that the url that I'm connection to may timeout. Therefore, I would like to set a timeout, like 15 secs. If so, trigger a listener.
However, I haven't seen any timeout features in the documentation for http.createClient. Please advise. Thanks. :)
var foo = setTimeout(function() {
request.emit("timeout-foo");
}, 15000);
// listen to timeout
request.on("timeout-foo", function() { });
request.addListener('response', function (response) {
// bla
// clear counter
clearTimeout(foo);
});
Just run the counter yourself.
Related
I have a server
var connect = require('connect');
var serveStatic = require('serve-static');
var HTMLServer = function(path){
this.path = path;
this.server = connect().use(serveStatic(this.path));
this.startServer = function(callback){
this.server = this.server.listen(8080, callback);
};
this.stopServer = function(callback){
this.server.close(callback);
}
}
And I use it as follows:
var thisServer = new HTMLServer(__dirname);
thisServer.startServer(function(){
console.log('Server running on 8080...');
setTimeout(function(){
thisServer.stopServer(function(){
console.log('Server closed');
});
}, 3000);
});
As expected, server starts and after 3000 milliseconds it stops.
But, if within these 3000 milliseconds I make a request to this server, the stopServer is called, however the server is not closed.
I'm sure this line this.server.close(callback); gets executed, but doesn't close the server as I expect.
How can I fix that?
Is a request to the server changing the server instance in a way that needs a special handling?
Later edit:
I would like to add some precision now that I left the code running. It seems the server does get closed, however not instantly, but after an amount of time that I don't understand, no longer than 5 minutes.
So the close operation seems to be delayed. Can I make it instant somehow?
While #jfriend00 was correct that node.js keeps running until all exiting sockets are finished, the process.exit solution was a bit too radical for my use case and I needed a cleaner solution to close the server gracefully.
Looking into getConnections only added more confusion since it didn't function as expected. (for example it returned 2 connections even if I didn't make any request).
I also looked into server.listening but it returned false even if the server accepted more requests. Perhaps accepts connection from a client that made requests before closing the server.
Anyway, the solution for me was to use the http-shutdown lib which essentially adds the following .shutdown method to your server object.
function addShutdown(server) {
var connections = {};
var isShuttingDown = false;
var connectionCounter = 0;
function destroy(socket, force) {
if (force || (socket._isIdle && isShuttingDown)) {
socket.destroy();
delete connections[socket._connectionId];
}
};
function onConnection(socket) {
var id = connectionCounter++;
socket._isIdle = true;
socket._connectionId = id;
connections[id] = socket;
socket.on('close', function() {
delete connections[id];
});
};
server.on('request', function(req, res) {
req.socket._isIdle = false;
res.on('finish', function() {
req.socket._isIdle = true;
destroy(req.socket);
});
});
server.on('connection', onConnection);
server.on('secureConnection', onConnection);
function shutdown(force, cb) {
isShuttingDown = true;
server.close(function(err) {
if (cb) {
process.nextTick(function() { cb(err) });
}
});
Object.keys(connections).forEach(function(key) {
destroy(connections[key], force);
});
};
server.shutdown = function(cb) {
shutdown(false, cb);
};
server.forceShutdown = function(cb) {
shutdown(true, cb);
};
return server;
};
With this function, I can update my server as follows, and now stopServer works as expected:
var HTMLServer = function(path){
this.path = path;
this.server = connect().use(serveStatic(this.path));
this.startServer = function(callback){
this.server = addShutdown(this.server.listen(8080, callback));
};
this.stopServer = function(callback){
console.log("I was called");
this.server.shutdown(callback);
}
}
I need to make an HTTP call and then put the response in database. i should repeat it forever. i have been reading on async module but i didn't understood how to combine these actions along with the waiting for couple of seconds between each iteration.
Can someone help?
Thanks in advance.
Look into async.forever. Your code would look something like this:
var async = require("async");
var http = require("http");
//Delay of 5 seconds
var delay = 5000;
async.forever(
function(next) {
http.get({
host: "google.com",
path: "/"
}, function(response) {
// Continuously update stream with data
var body = "";
response.on("data", function(chunk) {
body += chunk;
});
response.on("end", function() {
//Store data in database
console.log(body);
//Repeat after the delay
setTimeout(function() {
next();
}, delay)
});
});
},
function(err) {
console.error(err);
}
);
Why using such a module only for doing this ? Why don't you just use setTimeout like:
function makeRequest() {
request(url, function(response) {
saveInDatabase(function() {
// After save is complete, use setTimeout to call again
// "makeRequest" a few seconds later (Here 1 sec)
setTimeout(makeRequest, 1000);
});
}
}
This code won't really work for the request and save part of course, it was just to give an example of what I was proposing.
I have the following PHP Script on server that will wait 10 seconds and say Hello:
<php sleep(10); ?>Hello
On the client side (node), I have the following:
var http = require('http');
http.get ('http://example.com/sleep.php', function (resp) {
resp.on('data', function (d) {
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
});
The problem is, if the internet connection stopped during the request, it will not trigger error OR end events.
To re-produce the problem:
Place the PHP script somewhere on the Internet
Execute the node script
Disconnect the Internet
The script does nothing
I've also found that if the connection is back within 10 seconds, it can still receive the message.
So, I made a simple interval loop to check the status. However it can't detect if the connection has stopped working or still waiting for response:
var http = require('http');
var lastRespond = 0, intervalCheck;
var respFinished = false;
http.get ('http://jixun.no-ip.org/sleep.php', function (resp) {
resp.on('data', function (d) {
lastRespond = new Date;
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
respFinished = true;
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
});
intervalCheck = setInterval(function () {
if (respFinished) {
clearInterval(intervalCheck);
} else if (new Date - lastRespond >= 120000) {
console.log ('Timeout :(');
clearInterval(intervalCheck);
}
}, 120000); // 2 mins.
So my question is: Is there any way to check if the socket closed / connection stopped after sending the request?
Thanks in advance.
Using setTimeout on the actual request could solve your problem. Well, it's not an actual event like 'close', 'end' and 'error'. Sample below does reproduce and solves the issue, haven't tried it in another context though.
var http = require('http');
http.get ('http://fake-response.appspot.com?sleep=5', function (resp) {
resp.on('data', function (d) {
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
}).setTimeout(12000, function ( ) {
console.log('Timeout reached...');
process.exit(1);
});
More information can be found in the documentation. Either use that or listening on the 'close' event as well, that works well with the net module.
Maybe this would be usefull for you:
Create a bash script which checks connection (grabbed from https://stackoverflow.com/a/14939373/1779015 with little modifications):
#!/bin/bash
# Test for network conection
for interface in $(ls /sys/class/net/ | grep -v lo);
do
if [[ $(cat /sys/class/net/$interface/carrier 2> /dev/null) = 1 ]]; then OnLine=1; fi
done
if ! [ $OnLine ]; then echo "0";
else
echo "1";
fi
Then call it from node script and read stdout, for example with child_process (http://nodejs.org/api/child_process.html):
var spawn = require('child_process').spawn,
hasInet = spawn('./test-inet.sh');
hasInet.stdout.pipe(process.stdout);
Here is my solution ... instead of using set interval I check if on "data" event keeps firing until END event.
var http = require('http');
var url = require('url');
var options = {};
var parsed_url = url.parse(url, true);
var req_options = {
path: parsed_url.pathname,
host: parsed_url.hostname
};
var file = fs.createWriteStream(filename,options);
try{
const check_data_timeout = 10000;
var check_data_timer = 0;
var current_size = 0;
var request = http.get(req_options, function(response) {
len = parseInt(response.headers['content-length'], 10);
response.on("data", function(chunk) {
current_size += chunk.length;
percent = (100.0 * current_size / len).toFixed(2);
console.log("Download percent : "+percent+"%");
clearTimeout(check_data_timer);
check_data_timer = setTimeout(function(){
console.log("UPS !! No new data ... connection must be stalled");
},check_data_timeout);
});
response.on("end", function() {
console.log("Response ENDED !!!");
clearTimeout(check_data_timer);
});
response.pipe(file);
check_data_timer = setTimeout(function(){
console.log("UPS !! No new data ... connection must be stalled");
},check_data_timeout);
}).once('error', function(error) {
console.log("Response ERROR !!!");
});
}catch(e){
console.log(e);
}
Hope it helps ...
I'm new to node.js, and I'm trying to call a service, parse its data and return it as part of a view. I can't seem to get the request to block until the response is complete. The console always logs 'wrong' before 'right' (returning the 1,2,3 array). What am I missing?
app.js
var reading = require('./reading');
app.get('/reading', function(req, res){
res.render('reading/index.stache',
{
locals : { ids : reading.list},
partials : {
list : '{{#ids}}{{.}}<br />{{/ids}}'
}
});
});
reading.js
var request,
http = require('http'),
host = 'google.com',
path ='/';
var list = function(){
var connection = http.createClient(80, host),
request = connection.request(path);
request.addListener('response', function(response){
var data = '';
response.addListener('data', function(chunk){
data += chunk;
});
response.addListener('end', function(){
console.log('right')
//var results = JSON.parse(data);
// i need results from json
return [88234,883425,234588];
});
});
request.end();
console.log('wrong');
return [1,2,3];
}
module.exports.list = list;
Of course you can't get the request to block until the response is back.
That's because there is communication latency between sending the request of and getting the response back. It would be stupid to wait and do nothing whilst that latency is happening.
Use callbacks and asynchronous control flow.
var list = function(callback){
var connection = http.createClient(80, host),
request = connection.request(path);
request.addListener('response', function(response){
var data = '';
response.addListener('data', function(chunk){
data += chunk;
});
response.addListener('end', function(){
console.log('right')
// USE A CALLBACK >:(
callback([88234,883425,234588]);
});
});
request.end();
}
If you wan't to run anything in sync have a look at the sync module. It's based on fibers.
i'm trying to write a simple app with node.js to pull some json from twitter..
json loads ok the first time, however, my 'tweets' event isnt getting triggered correctly..
anyone see where I'm going wrong? any advice hugely appreciated !
var twitterClient = http.createClient(80, 'api.twitter.com');
var tweetEmitter = new events.EventEmitter();
var request = twitterClient.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
function getTweats() {
request.addListener("response", function (response) {
var body = "";
response.addListener("data", function (data) {
body += data;
});
response.addListener("end", function (end) {
var tweets = JSON.parse(body);
if (tweets.length > 0) {
tweetEmitter.emit("tweets", tweets);
console.log(tweets, 'tweets loaded');
}
});
});
request.end();
}
setInterval(getTweats(), 1000);
http.createServer(function (request, response) {
var uri = url.parse(request.url).pathname;
console.log(uri);
if (uri === '/stream') {
var cb = function (tweets) {
console.log('tweet'); // never happens!
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify(tweets));
response.end();
clearTimeout(timeout);
};
tweetEmitter.addListener("tweets", cb);
// timeout to kill requests that take longer than 10 secs
var timeout = setTimeout(function () {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify([]));
response.end();
tweetEmitter.removeListener("tweets", cb);
}, 10000);
} else {
loadStaticFile(uri, response);
}
}).listen(port);
console.log("Server running at http://localhost:" + port + "/");
see full file # https://gist.github.com/770810
You have two problems here:
httpClient.request is just that, a one time request.
You're not passing the function getTweats to the interval, but its return value:
setInterval(getTweats() */ <-- parenthesis execute the function */, 1000);
In order to fix it, create a new request for each call of getTweats:
function getTweats() {
// There's no need for request being global, just make it local to getTweats
var request = twitterClient.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
And pass the function correctly to setTimeout:
setInterval(getTweats, 1000);
PS: Thx for the gist! Took me like 15 seconds to figure it out from there, always great when people post more than just 5 lines of out of context code :)