Hi, I'm seeking for a way to shutdown a server. The current behavior is, when I call close() on engine, clients disconnect, but connect again immediately. Even if I call socket.io.close() on disconnect, the server is still listening.
And, can I suppose if socket.io.close() is called,(and references from my program is all deleted), the socket will be subject to garbage collection?
"use strict"
var svr = require('socket.io')(12332);
var clt1 = require('socket.io-client')('ws://127.0.0.1:12332');
var clt2 = require('socket.io-client')('ws://127.0.0.1:12332');
svr.on('connection', function(socket) {
console.log("svr connected");
svr.engine.close();
});
clt1.on('connect', function() {
console.log('clt connected');
});
clt1.on('disconnect', function() {
console.log('clt disconnected');
// clt1.io.close();
});
clt1.on('error', function() {
console.log('clt error');
});
ok, I've read some code and found socket.destroy() for the client.
@msmouse is socket.destroy()
working well for you? Hoping to close this issue
I'm experiencing this problem as well. Calling close on the http server does make it stop accepting new connections, but the http server never fires its close event, so the close callback never gets evoked. If I shutdown without anyone connecting, then the server closes fine, but once a single person has connected the server refuses to shutdown cleanly.
I've tried io.close()
, io.engine.close()
. I'm sending a shutdown command to all clients, which causes the frontend to close on its end, and then I see the socket disconnecting, so I know the sockets are all closed.
For whatever reason, the http server never realizes that all connections are complete. This is a pretty big issue for me, since I can't safely close my database links until I know all requests have finished and http is clear.
:+1:
+1
I think a problem is, that the httpServer.close()
is async here.
So the server
should bind to the httpServer
close event.
Workaround:
ioClosed = new Promise (resolve) ->
if io.httpServer
io.httpServer.on "close", resolve
else
resolve()
+1
+1
Busy server has always active websocket connections, there must be a way to shutdown the server cleanly without expecting any co-operation from the clients? I mean assuming I have:
let io = socketIo(server);
io.on('connection', function(socket) {
[add socket to active sockets list]
[all other logic]
socket.on('disconnect', function() {
[remove socket from active sockets list]
});
}
Then in shutdown this should work?
// 1.
io.close() // Stop accepting new connections
// 2.
for [all items in active sockets list] {
socket.disconnect() // <- This doesn't close the underlying TCP socket.
}
But it doesn't.
Just spent way too much time struggling with this, but I had success with the following:
function wireUpServer(/*httpServer*/ server) {
var connections = {};
server.on('connection', function(conn) {
var key = conn.remoteAddress + ':' + conn.remotePort;
connections[key] = conn;
conn.on('close', function() {
delete connections[key];
});
});
server.destroy = function(cb) {
server.close(cb);
for (var key in connections)
connections[key].destroy();
};
}
Then during your init process you can call:
wireUpServer(server)
and when you're ready to destroy
io.close();
server.destroy();
The connection tracking/destruction taken from here: https://github.com/isaacs/server-destroy/blob/master/index.js
Similar logic here for a plain old net.Server
.
Given that socket.io tries to abstract away a lot of the underlying network tomfoolery, it'd be great if it came with this feature baked in.
I'm also experiencing this issue. socket.io v1.4.5. Here's code to reproduce it:
server-hang.js
:
(function() {
"use strict";
var PORT = 5020;
var TIMEOUT = 10000;
var io = require('socket.io')(PORT);
console.log("Waiting " + (TIMEOUT / 1000) + " seconds...");
setTimeout(function() {
io.close();
console.log("PROCESS SHOULD NOW EXIT");
}, TIMEOUT);
}());
server-hang.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Server won't exit</title>
<meta charset="utf-8">
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
</head>
<body>
<p>Look at the console!</p>
<script>
console.log("Client started");
console.log("Connecting...");
var origin = "http://localhost:5020";
var socket = io(origin);
socket.on("connect", function() {
console.log("Server connected");
socket.disconnect();
console.log("disconnect() called");
});
</script>
</body>
</html>
To reproduce:
node server-hang.js
server-hang.html
into a browser window. It will load as a file resource and trigger the bug.Expected behavior: The server should exit after 10 seconds.
Update: the server _does_ exit if the browser is closed, but not if the tab is closed. (Confirmed on Mac OS using Firefox, Chrome, and Safari.)
Update 2: Destroying the connections server-side, as suggested in https://github.com/socketio/socket.io/issues/1602#issuecomment-120561951, _does_ work. But it won't work when using the bare io(origin)
constructor like my example does. You have to create an Node HTTP server and listen for connections to the Node server.
Also have this bug.
My code is similar to @jamesshore
I have tracked down the cause of this, it is indeed a bug.
The ws
package that engine.io uses has the following block inside of a close
method
src: https://github.com/websockets/ws/blob/master/lib/WebSocket.js#L125-L131
As you can see from the overlay, the _closeReceived
property never gets set to true
at any point by socket.io or engine.io, this means the terminate()
method is never called and instead we enter into a 30 second wait
// socket.io/engine.io never sets `self._closeReceived` to true, so we can never get into this block
// to call the terminate method
if (self._closeReceived && self._isServer) {
self.terminate();
} else {
// WE ALWAYS REACH HERE
// and closeTimeout = 30 seconds
clearTimeout(self._closeTimer);
self._closeTimer = setTimeout(cleanupWebsocketResources.bind(self, true), closeTimeout);
}
The chain of events that lead to this bug begin here https://github.com/socketio/engine.io/blob/master/lib/server.js#L180-L188
Here's a screencast showing the stack https://www.youtube.com/watch?v=H0ngC6TDePE&feature=youtu.be
@rauchg @3rd-Eden @einaros is there any extra information you would need?
This is a big problem for tools such as Browsersync as we want to allow users to gracefully boot up/shut down servers at will, and currently if any socket is connected, they will be doomes to the 30000
wait timeout as shown above.
Many thanks for your hard on this lib, please inform me if you need any further information.
Any update on this issue?
A part of the problem is, that a httpserver
will not close as long as there are connections alive:
https://nodejs.org/api/http.html#http_server_close_callback
A proper closing mechanism would need to keep track of all connections - which is probably out of scope of socketio.
// will close the underlying httpserver - that means it wont accept new connections
// but as long as there are open connections, it won't actually close
io.httpServer.close()
// will close all active websocket sessions - but not the connections
io.close()
Just use the solution presented above..
Any news on this issue?
Nevermind, sorry for the above question, I realise the solution presented above actually works. I was just having issues with closing socket.io server when clients are still connected and thought the problem was still here in engine.io.
@nguiard ,i aslo found the issue is still existed.
Is this module still maintained? We facing the same error. None of the suggested codes work around the problem. In fact in my case there is no client connected. 馃樋
For anyone wanting their server to clean up active connections, I made a package: https://www.npmjs.com/package/socket.io-fix-close
Hi quick question here @s-a do you experienced EARDDRESINUSE? or the port is still in use ? When use nodemon or others?
This issue still exists.... Ctrl-C killing the server would still persist the socket connections, and upon refresh of client, it will ask for another new socket + reconnecting the old socket... the server is not disconnected from the first connection, another refresh will trigger an extra socket...
https://github.com/socketio/socket.io/issues/1602#issuecomment-120561951
I am using the following with Set
instead of an object (and delete
):
const connections = new Set();
server.on("connection", connection => {
connections.add(connection);
connection.once("close", () => {
connections.delete(connection);
});
});
const shutdownHandler = once(() => {
console.log("Shutting down");
httpServer.close(err => {
if (err) {
console.error(err);
process.exitCode = 1;
}
});
for (const connection of connections) {
connection.destroy();
}
});
process.on("SIGINT", shutdownHandler);
@n1ru4l does this work for you?
I have done a similar solution but I get destroy is not a function
.
There is a disconnect
property on the socket but calling that does not make the server shut down.
It works (for us).
Most helpful comment
Just spent way too much time struggling with this, but I had success with the following:
Then during your init process you can call:
and when you're ready to destroy
The connection tracking/destruction taken from here: https://github.com/isaacs/server-destroy/blob/master/index.js