question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

createAdapter(pubClient, subClient) breaks subClient.connect(): "Error: Cannot send commands in PubSub mode"

See original GitHub issue

package.json

    "@socket.io/redis-adapter": "7.1.0",
    "redis": "4.0.1",
    "socket.io": "4.4.0"

The Redis itself is running in Docker with the image redis:6.2.6-alpine3.15.

Here is the code that doesn’t work for some reason:

import { Server } from 'socket.io'
import { createClient } from 'redis'
import { createAdapter } from '@socket.io/redis-adapter'

const io = new Server()
const pubClient = createClient({url: `redis://redis:6379/1`})
const subClient = pubClient.duplicate()

io.adapter(createAdapter(pubClient, subClient))

Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.listen(9003)
  console.log('Listening on port 9003...')

  async function redisTest() {
    await subClient.subscribe('channel', (message) => {
      console.log('Received message', message)
    })
    await pubClient.publish('channel', 'Hello')
    await pubClient.publish('channel', 'World!')
  }
  redisTest()
})

The code gives me the following error:

/code/node_modules/@node-redis/client/dist/lib/client/commands-queue.js:68
            return Promise.reject(new Error('Cannot send commands in PubSub mode'));
                                  ^

Error: Cannot send commands in PubSub mode
    at RedisCommandsQueue.addCommand (/code/node_modules/@node-redis/client/dist/lib/client/commands-queue.js:68:35)
    at RedisSocket.socketInitiator (/code/node_modules/@node-redis/client/dist/lib/client/index.js:304:81)
    at RedisSocket._RedisSocket_connect (/code/node_modules/@node-redis/client/dist/lib/client/socket.js:122:77)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Commander.connect (/code/node_modules/@node-redis/client/dist/lib/client/index.js:156:9)
    at async Promise.all (index 1)

If I remove the line io.adapter(createAdapter(pubClient, subClient)), it starts working again:

Listening on port 9003...
Received message Hello
Received message World!

If I remove the subClient.connect(), but leave the adapter, it doesn’t crash, but I obviously won’t receive the published messages:

Listening on port 9003...

Do I just need to downgrade some packages or why might I have this problem? It feels like the README is using outdated packages, as an example, the Redis createClient now takes the url option instead of the host and port mentioned in the README.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
akifdcommented, Dec 14, 2021

Hmm it seems to work if I move the io.adapter() after connecting the Redis clients:

import { Server } from 'socket.io'
import { createClient } from 'redis'
import { createAdapter } from '@socket.io/redis-adapter'

const io = new Server()
const pubClient = createClient({url: `redis://redis:6379/1`})
const subClient = pubClient.duplicate()

Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.adapter(createAdapter(pubClient, subClient))
  io.listen(9003)
  console.log('Listening on port 9003...')

  async function redisTest() {
    await subClient.subscribe('channel', (message) => {
      console.log('Received message', message)
    })
    await pubClient.publish('channel', 'Hello')
    await pubClient.publish('channel', 'World!')
  }
  redisTest()
})

Is this intentional? If yes, the documentation should be updated to reflect this.

1reaction
darrachequesnecommented, Jan 4, 2022

OK, so I’ve updated the README and the documentation on the website: https://socket.io/docs/v4/redis-adapter/

Thanks for the heads-up!

Read more comments on GitHub >

github_iconTop Results From Across the Web

0 - Stack Overflow
I have a few questions: Why doesn't the Redis Client reconnect? The pubClient reconnects after errors consistently, but the subClient does not.
Read more >
Going Real-Time with Redis Pub/Sub - Toptal
Exploring the architecture of a simple web app that works using Redis Pub/Sub and doesn't compromise horizontal scalability.
Read more >
Redis adapter - Socket.IO
The Redis adapter relies on the Redis Pub/Sub mechanism. Every packet that is sent to multiple clients (e.g. io.to("room1").emit() or ...
Read more >
Redis Pub/Sub
A client subscribed to one or more channels should not issue commands, although it can subscribe and unsubscribe to and from other channels....
Read more >
Socket.io-redis NPM
adapter(createAdapter({ pubClient, subClient }));. By running Socket.IO with the socket.io-redis adapter you can run multiple Socket.IO instances in different ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found