Using node.js http.createServer to listen POST requests. If request completes fast, all works good. If request complete time > 5 seconds i get no response returned to client.
Added event listeners on created sockets:
server.on('connection', function(socket) {
log.info('SOCKET OPENED' + JSON.stringify(socket.address()));
socket.on('end', function() {
log.info('SOCKET END: other end of the socket sends a FIN packet');
});
socket.on('timeout', function() {
log.info('SOCKET TIMEOUT');
});
socket.on('error', function(error) {
log.info('SOCKET ERROR: ' + JSON.stringify(error));
});
socket.on('close', function(had_error) {
log.info('SOCKET CLOSED. IT WAS ERROR: ' + had_error);
});
});
Got those messages on middle of request (after about 10 sec after start):
info: SOCKET TIMEOUT
info: SOCKET CLOSED. IT WAS ERROR: false
But on client socket do not get closed, so client wait for response. End of request completed with success, response sent (on closed socket!), but client still wait.
No idea how to block those timeouts. Removed all timeouts from code. Tried to add KeepAlive, no result.
socket.setKeepAlive(true);
How to prevent socket bultin timeout?
From node's setTimeout documentation the connection will not be severed when a timeout occurs. That's why the browser's still waiting. You're still required to end() or destroy() the socket. You can increase the timeout by calling setTimeout on the socket.
socket.setTimeout(1000 * 60 * 300); // 5 hours
You can do a couple of things:
socket.setTimeout(/* number of milliseconds */);
If you do this, then the server can get a timeout event:
server.on('timeout', function(timedOutSocket) {
timedOutSocket.write('socket timed out!');
timedOutSocket.end();
});
Related
currently I am using the following code in node.js with socket.io to connect to my server, which is working fine. But if my node.js server is not running, the client is trying to connect to it again and again in intervals - but I would like to stop it and close the socket on the client side if the server is not reachable. I have tried using connect_failed, but unfortunately this is never being called. how can this be done?
function findOpponent(gamemode)
{
console.log('Registering myself on nodejs Server and waiting for 2nd player');
socket = io.connect("http://gladiator.localhost:3000" , {
'query': '&uuid='+uuid+'&authkey='+auth_key+'&gamemode='+gamemode
});
socket.on('connect_failed', function() {
// --> this is never being called
console.log("Sorry, there seems to be an issue with the connection!");
});
socket.on('user join',function(msg){
alert('USER JOINED');
});
socket.on('user leave',function(msg){
console.log(msg);
alert('USER LEFT');
});
socket.on('message',function(msg){
alert(msg);
});
socket.on('gamestart',function(data){
console.log('gamestart');
alert(data.msg);
});
}
try autoConnect and reconnection options for socket io client
{ autoConnect: false, reconnection: false}
EDIT:
and you can listen on connect_error event for catch connection error
socket.on("connect_error", callback)
What i'm trying to do from my tests is to simulate ETIMEDOUT that should be caught by socket.on('error', () => {...}). In real word with 3rd party TCP server that im using, ETIMEDOUT is always caught by error event. Would like to mimic this situation in my tests also. Going through the tls docs, only candidate that could be used for this purpose is socket.setTimeout but it does not work how i would expect it:
describe('TCP timeout', () => {
const TIMEOUT_AFTER_IN_MILLISECONDS = 1
const socket = getActiveSocketFromSomewhere()
it('should simulate timeout', () => {
socket.setTimeout(TIMEOUT_AFTER_IN_MILLISECONDS, () => {
console.log('are we here')
})
/**
* This will trigger socket communication
* with dummy TCP server where socket from
* above will be used
*/
return something()
...
})
})
From console i can see that i was waiting for answer for 14ms and that callback provided to setTimeout was executed, but after i can see that i received response from TCP server:
are we here
{ result: 'success', ... }
Yes, That's how the behavior is.
When the timeout is reached, the socket is not ended explicitly. It is clearly mentioned in the document and you'll receive a response whenever it is destined
https://nodejs.org/dist/latest-v6.x/docs/api/net.html#net_socket_settimeout_timeout_callback
If you want to end the socket, you need to manually call socket.end() or socket.destroy() after timeout event is triggered
Code:
socket.on('timeout',function(){
socket.end();
})
I am trying to make a chat app which sends first message as "Hi. there".
But due to some some reasons (unstable internet connection might be one) the socket get initialized multiple times and sends the "Hi. there" message multiple times. Below is the code. How to stop the app for sending multiple messages?
io.socket.on('connect', function() {
/* On successfull connection to server */
console.log('Connected to server');
//Some code here
io.socket.get(url + '/userstatus/subscribe', function(resData, jwres) {
//Some code here
io.socket.on("userstatus", function(event) {
//Socket updartes
// Send Message code at this line.
}
}
});
You need to change your client side code, so that it stores state, and sends it to the server on reconnect. That way the server can give the correct response.
Something like this might work:
socket.on('connect', function() {
/* On successfull connection to server */
console.log('Connected to server');
socket.emit('state', state_object);
});
I am trying to 'gracefully' close a net.Server instance (created with app.listen()) if an un-handled error is thrown. Server creation occurs in my bin/www script. All error handling and routing middleware configuration is defined in index.js.
In my application configuration module (index.js) I have error handling middleware that checks that each error is handled. If the error is not handled then a 'close' event is emitted.
Note: Each req and res is wrapped in a domain. I am using express-domain-middleware middleware module to listen for error events on each req domain and route the error to my error handling. I only mention this in case it might be the culprit.
The 'close_server' event handler should:
Close the server so new connections are not accepted.
Close the current process once all open connections have completed.
If after 10 seconds the server has not closed, force the process to close.
The optional callback provided to server.close() never seems to be invoked and I'm not sure why. To test this I am making a single request which throws an error. The process is only closed after the timer expires (10 seconds has elapsed).
Could there be something holding open a connection in the server? Why is the server.close() callback never called?
Thanks!
Update
I was using Chrome to make a request to the server. It appears that the browser is holding open a connection. If I make the request using curl it works as expected.
See this issue
index.js
app.use(function (err, req, res, next) {
if (typeof err.statusCode !== 'undefined') {
if (err.statusCode >= 500) {
Logger.error({error: err});
return next(err);
} else {
Logger.warn({warn: err});
return next(err);
}
} else {
//The error is un-handled and the server needs to go bye, bye
var unhandledError = new UnhandledError(util.format('%s:%s', req.method, req.originalUrl), 'Server shutting down!', err.stack, 500);
Logger.fatal({fatal: unhandledError});
res.status(500).send('Server Error');
app.emit('close_server', unhandledError);
}
});
bin/www
#!/usr/bin/env node
var app = require('../index');
var port = config.applicationPort;
app.set('port', port);
var server = app.listen(app.get('port'));
/*
* Wait for open connections to complete and shut server down.
* After 10 seconds force process to close.
* */
app.on('close_server', function () {
server.close(function () {
console.log('Server Closed.');
process.exit()
});
setTimeout(function () {
console.log('Force Close.');
process.exit()
}, 10 * 1000);
});
server.close() does not close open client connections, it only stops accepting new connections.
So most likely Chrome is sending a request with Connection: keep-alive which means the connection stays open for some time for efficiency reasons (to be able to make multiple requests on the same connection), whereas curl is probably using Connection: close where the connection is severed immediately after the server's response.
As #mscdex mentioned server.close never runs its callback when the browser sends the request Connection: keep-alive, because server.close only stops the server from accepting new connections.
Node v18.2.0 introduced server.closeAllConnections() and server.closeIdleConnections()
server.closeAllConnections() closes all connections connected to the server, and server.closeIdleConnections() closes all connections connected to the server but only the ones which are not sending a request or waiting for a response.
Before Node v18.2.0 I tackled this problem by waiting 5 seconds for the server to shutdown, after which it would force exit.
The following code contemplates both situations
process.on('SIGINT', gracefulShutdown)
process.on('SIGTERM', gracefulShutdown)
function gracefulShutdown (signal) {
if (signal) {
console.log(`\nReceived signal ${signal}`)
}
console.log('Gracefully closing http server')
// closeAllConnections() is only available after Node v18.02
if (server.closeAllConnections) server.closeAllConnections()
else setTimeout(() => process.exit(0), 5000)
try {
server.close(function (err) {
if (err) {
console.error(err)
process.exit(1)
} else {
console.log('http server closed successfully. Exiting!')
process.exit(0)
}
})
} catch (err) {
console.error('There was an error', err)
setTimeout(() => process.exit(1), 500)
}
}
I'm building a small prototype with node.js and socket.io. Everything is working well, the only issue I'm facing is that my node.js connection will disconnect and I'm forced to refresh the page in order to get the connection up and running again.
Is there a way to reestablish the connection as soon as the disconnect event is fired?
From what I've heard, this is a common issue. So, I'm looking for a best-practice approach to solving this problem :)
Thanks very much,
Dan
EDIT: socket.io now has built-in reconnection support. Use that.
e.g. (these are the defaults):
io.connect('http://localhost', {
'reconnection': true,
'reconnectionDelay': 500,
'reconnectionAttempts': 10
});
This is what I did:
socket.on('disconnect', function () {
console.log('reconnecting...')
socket.connect()
})
socket.on('connect_failed', function () {
console.log('connection failed. reconnecting...')
socket.connect()
})
It seems to work pretty well, though I've only tested it on the websocket transport.
edit: Socket.io has builtin-support now
When I used socket.io the disconnect did not happen(only when i closed the server manually). But you could just reconnect after say for example 10 seconds on failure or something on disconnect event.
socket.on('disconnect', function(){
// reconnect
});
I came up with the following implementation:
client-side javascript
var connected = false;
const RETRY_INTERVAL = 10000;
var timeout;
socket.on('connect', function() {
connected = true;
clearTimeout(timeout);
socket.send({'subscribe': 'schaftenaar'});
content.html("<b>Connected to server.</b>");
});
socket.on('disconnect', function() {
connected = false;
console.log('disconnected');
content.html("<b>Disconnected! Trying to automatically to reconnect in " +
RETRY_INTERVAL/1000 + " seconds.</b>");
retryConnectOnFailure(RETRY_INTERVAL);
});
var retryConnectOnFailure = function(retryInMilliseconds) {
setTimeout(function() {
if (!connected) {
$.get('/ping', function(data) {
connected = true;
window.location.href = unescape(window.location.pathname);
});
retryConnectOnFailure(retryInMilliseconds);
}
}, retryInMilliseconds);
}
// start connection
socket.connect();
retryConnectOnFailure(RETRY_INTERVAL);
serverside(node.js):
// express route to ping server.
app.get('/ping', function(req, res) {
res.send('pong');
});
Start reconnecting even if the first attempt fails
If the first connection attempt fails, socket.io 0.9.16 doesn't try to reconnect for some reason. This is how I worked around that.
//if this fails, socket.io gives up
var socket = io.connect();
//tell socket.io to never give up :)
socket.on('error', function(){
socket.socket.reconnect();
});
I know this has an accepted answer, but I searched forever to find what I was looking for and thought this may help out others.
If you want to let your client attempt to reconnect for infinity (I needed this for a project where few clients would be connected, but I needed them to always reconnect if I took the server down).
var max_socket_reconnects = 6;
var socket = io.connect('http://foo.bar',{
'max reconnection attempts' : max_socket_reconnects
});
socket.on("reconnecting", function(delay, attempt) {
if (attempt === max_socket_reconnects) {
setTimeout(function(){ socket.socket.reconnect(); }, 5000);
return console.log("Failed to reconnect. Lets try that again in 5 seconds.");
}
});