-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
no way to shutdown a server cleanly #1602
Comments
ok, I've read some code and found socket.destroy() for the client. |
@msmouse is |
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 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 I think a problem is, that the Workaround: ioClosed = new Promise (resolve) ->
if io.httpServer
io.httpServer.on "close", resolve
else
resolve() |
+1 |
1 similar comment
+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:
Then in shutdown this should work?
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 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:
(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);
}());
<!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:
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 #1602 (comment), does work. But it won't work when using the bare |
Also have this bug. My code is similar to @jamesshore |
I have tracked down the cause of this, it is indeed a bug. The src: https://github.com/websockets/ws/blob/master/lib/WebSocket.js#L125-L131 As you can see from the overlay, the // 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 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 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, based on ilkovich's snippet: |
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... |
New version of socket.io cannot terminate cleanly when there are active connections: socketio/socket.io#1602
I am using the following with 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? |
This might help.. added in socket v4 |
I still experience server hang-when-close with socket.io v4.7.4 . Cutting underlying TCP connection still work, calling This is a renewed snippet of the TCP connection trick, thanks for information in this thread. import type net from 'node:net';
import type http from 'node:http';
/**
* record alive TCP connections, to force disconnect them during shutdown
* (socket.io may have problem close all connections.)
* @return a function to close all TCP sockets
*/
export function prepareTcpConnect(server: http.Server): () => void {
const sockets = new Set<net.Socket>();
server.on('connection', conn => {
sockets.add(conn);
conn.on('close', () => {
sockets.delete(conn);
});
});
return () => sockets.forEach(s => s.destroy());
} |
@jokester I don't think this should be needed. Isn't Lines 745 to 760 in e36062c
It should close both:
Also, I was not able to reproduce the issue: // server.js
import { createServer } from "node:http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {});
const port = process.env.PORT || 3000;
io.on("connection", (socket) => {
console.log(`connect ${socket.id}`);
socket.on("disconnect", (reason) => {
console.log(`disconnect ${socket.id} due to ${reason}`);
});
});
io.of("/chat").on("connection", (socket) => {
console.log(`[chat] connect ${socket.id}`);
socket.on("disconnect", (reason) => {
console.log(`[chat] disconnect ${socket.id} due to ${reason}`);
});
});
httpServer.listen(port, () => {
console.log(`server listening at http://localhost:${port}`);
});
setTimeout(() => {
io.close();
console.log("PROCESS SHOULD NOW EXIT");
}, 10_000); // client.js
import { io } from "socket.io-client";
const port = process.env.PORT || 3000;
const socket = io(`http://localhost:${port}`);
socket.on("connect", () => {
console.log(`connect ${socket.id}`);
});
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
socket.on("disconnect", (reason) => {
console.log(`disconnect due to ${reason}`);
});
const socket2 = io(`http://localhost:${port}`, {
forceNew: true
});
const socket3 = io(`http://localhost:${port}/chat`, {
forceNew: true
});
const socket4 = io(`http://localhost:${port}`, {
forceNew: true,
transports: ["polling"]
});
const socket5 = io(`http://localhost:${port}`, {
forceNew: true,
transports: ["websocket"]
}); That being said, I only found one change impacting the |
@darrachequesne sorry I don't have a good reproduction or insight in code. When developing my app using socket.io I think my server stuck at 5% or 10% of all runs, until I cut the TCP sockets. I'm currently reading socket.io code to write an experimental adapter, maybe I can be lucky enough to find a hint 🤔 |
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');
});
The text was updated successfully, but these errors were encountered: