Skip to content

In shard mode, close throw error "CROSSSLOT Keys in request don't hash to the same slot" #500

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

Closed
ngot opened this issue May 10, 2023 · 3 comments
Labels
bug Something isn't working
Milestone

Comments

@ngot
Copy link

ngot commented May 10, 2023

I had a chance to try the new shard PubSub adapter. Mostly works good, but when enable cleanupEmptyChildNamespaces, the close function will throw "CROSSSLOT Keys in request don't hash to the same slot". The root cause is redis/node-redis#2502

Currently,

    close() {
        const channels = [this.channel, this.responseChannel];
        if (this.opts.subscriptionMode === "dynamic") {
            this.rooms.forEach((_sids, room) => {
                const isPublicRoom = !this.sids.has(room);
                if (isPublicRoom) {
                    channels.push(this.dynamicChannel(room));
                }
            });
        }
       // channels has at least 2 different strings, `sUnsubscribe` assumes 
       // they would be hashed to the same slot which is not correct.
       return this.subClient.sUnsubscribe(channels);
    }

A potential workaround

return Promise.all(channels.map((channel) => this.subClient.sUnsubscribe(channel)));
// return this.subClient.sUnsubscribe(channels);
@darrachequesne
Copy link
Member

Hi! Thanks for raising the issue, I'm digging into this.

@ngot
Copy link
Author

ngot commented May 11, 2023

According to redis/node-redis#2502 (comment), the sUnsubscribe(Array[]) assumes all the channels use "hash tags", so they are allocated to the same slot.

In socket.io-redis-adapter, there is dynamic channels, so sUnsubscribe one by one looks more doable.

Additionally, this is the usage of iosredis, it does not support array, but spread parameters.
https://github.com/luin/ioredis/blob/a3838ae7598c7d9d3aff688923403f6176d7a393/lib/utils/RedisCommander.ts#L8356

  /**
   * Stop listening for messages posted to the given shard channels
   * - _group_: pubsub
   * - _complexity_: O(N) where N is the number of clients already subscribed to a shard channel.
   * - _since_: 7.0.0
   */
  sunsubscribe(callback?: Callback<unknown>): Result<unknown, Context>;
  sunsubscribe(
    ...args: [
      ...shardchannels: (string | Buffer)[],
      callback: Callback<unknown>
    ]
  ): Result<unknown, Context>;
  sunsubscribe(
    ...args: [...shardchannels: (string | Buffer)[]]
  ): Result<unknown, Context>;

darrachequesne added a commit that referenced this issue May 14, 2023
Providing an array of channels to the SUNSUBSCRIBE command assumes all
the channels are allocated to the same slot, which is not always the
case, so we need to issue one command per channel.

Related: #500
@darrachequesne
Copy link
Member

This should be fixed by 2da8d9e, included in version 8.2.1.

@ngot thanks for the analysis 👍

@darrachequesne darrachequesne added this to the 8.2.1 milestone May 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants