socket.io-client icon indicating copy to clipboard operation
socket.io-client copied to clipboard

Subsequent new connections to previously closed namespaces results in new connections

Open sean256 opened this issue 3 years ago • 1 comments

Describe the bug When using namespaces, new "channels" are created over a shared connection as expected. But if a namespace calls socket.disconnect(); then later a new instance connects to the same namespace, a whole new connection will be made instead of multiplexing.

Before I get into it, I did find these existing issues: https://github.com/socketio/socket.io-client/issues/1514 https://github.com/socketio/socket.io-client/issues/1364 https://github.com/socketio/socket.io-client/issues/866 And finally the root cause: https://github.com/socketio/socket.io/issues/1956

After researching all of that, I believe this is a bug or more likely an unintended behavior. I understand #1956 and why opening a new connection to the same currently connected namespace is a thing, BUT, I really do not think this should happen if the previous channel was CLOSED.

I have a use case where my server code is using dynamic namespaces with regex, and the client is connecting to these dynamic namespaces using id's of various documents the user could browser to. So if my user loads document A, then B, then A again, it creates a new underlying connection. Since we have hundreds of possible id's and dynamic namespaces, caching each possible socket is not practical. This is just silly.

To Reproduce

(this code is not using dynamic namespaces as mentioned above, but it still demonstrates the issue)

Socket.IO server version: 4.5.1

Server

import { Server } from "socket.io";

const io = new Server(3000, {});

io.of("/namespace-a", (socket) => {
	// some logic
});


io.of("/namespace-b", (socket) => {
	// some logic
});

Client

import { io } from "socket.io-client";

const a = io("/namespace-a", {});
const b = io("/namespace-b", {});

// some time later
b.disconnect();

// some time later create a NEW connection to namespace-b
const newB = io("/namespace-b", {});

Expected behavior I expect all namespace channels to utilize a single connection.

Platform:

  • Device: Mac. Chrome & Safari
  • OS: MacOS & Docker Node 16.14.x

sean256 avatar Jun 20 '22 05:06 sean256

Simple workaround if this doesn't get addressed:

When manually disconnecting, remove the socket from the manager

socket.disconnect();
// @ts-ignore due to private property access
delete socket.io.nsps[socket.nsp];

Now when you create a new instance to the same namespace, multiplexing will work

sean256 avatar Jun 20 '22 20:06 sean256

For future readers:

I think trying to fix this problem will likely cause undesirable side effects, so I'm going to close this as "won't fix".

As a workaround, you can use the Manager directly:

import { Manager } from "socket.io-client";

const manager = new Manager("wss://example.com");

const a = manager.socket("/namespace-a", {});
const b = manager.socket("/namespace-b", {});

// some time later
b.disconnect();

// some time later create a NEW connection to namespace-b
const newB = manager.socket("/namespace-b", {});

See also:

  • https://github.com/socketio/socket.io-client/pull/1545
  • https://github.com/socketio/socket.io-client/commit/b7dd891e890461d33a104ca9187d5cd30d6f76af
  • https://github.com/socketio/socket.io-client/commit/46213a647ea0d4453b00bca09268f69ffd259509

darrachequesne avatar Apr 09 '24 18:04 darrachequesne