socket.io-redis-adapter icon indicating copy to clipboard operation
socket.io-redis-adapter copied to clipboard

dynamic subscription mode breaks socket.emit()

Open MartinKolarik opened this issue 1 year ago • 1 comments

When using the sharded adapter with subscriptionMode: "dynamic", messages sent to the socket's private room via socket.emit() get lost without any warning or error.

It happens because in this check, such messages look just like any other single-room broadcasts, so useDynamicChannel ends up being true but private rooms are excluded here so there are no subscribers.

I can see a couple of possible solutions here, but none is ideal:

  1. Attempt to identify the channel is private during emit, and set useDynamicChannel to false in such case. I made an attempt on this in #525 but it seems somewhat tricky.
  2. Clearly document that socket.emit() won't work in this mode.
  3. Remove the exception for private rooms and subscribe to them as well.
  4. Combination of 2 and 3 - add an option for subscribing to private rooms and document socket.emit() won't work without it.

MartinKolarik avatar Feb 13 '24 11:02 MartinKolarik

Upon further consideration, I think, regardless of this issue, it makes sense to have an option for creating separate channels for private rooms.

In our scenario, we have ~1k clients connected to ~10 servers, all communication is 1:1, and the connections stay open for a long time. Using separate channels significantly lowers the overall redis bandwidth, and the subscription/unsubscription impact shouldn't be significant. We could create our own "public" channel for each client, but using the existing ones seems like the cleanest option.

I implemented this, along with the previous fix, in #526. We're already running this in production, and it reduced the overall redis load by 50 - 60 % in our setup.

MartinKolarik avatar Feb 19 '24 09:02 MartinKolarik

Hi! I could indeed reproduce the issue, thanks for reporting this.

This happens when calling io.to(someSocketId).emit("hello"); (which is also what happens with a RemoteSocket, under the hood). Classic socket.emit()'s are not affected though.

darrachequesne avatar Feb 23 '24 09:02 darrachequesne

Classic socket.emit()'s are not affected though.

By this, you mean local emits? If yes, that's right, it only affects emits on remote sockets.

MartinKolarik avatar Feb 23 '24 20:02 MartinKolarik