You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis subClient调用psubscribe报错:TypeError: 该方法不存在

问题解决:Redis subClient.psubscribe 不是函数的错误

问题场景

在开发环境初始化Redis的pub/sub客户端用于Socket.io集群,代码如下:

if (process.env.STATUS === 'development') {
  const pubClient = redis.createClient({
    port: process.env.REDIS_PORT,
    host: process.env.REDIS_HOST,
  });
  const subClient = pubClient.duplicate();

  io.adapter(redisAdapter({ pubClient, subClient }));

  chatSocket(io, pubClient);
}

Socket连接处理代码:

import {setupChatSocket} from '../socket/serverEvents.js'

const chatSocket = function (io, pubClient) {
  let clients = JSON.parse(pubClient.get('clients'));
  if (!clients) clients = [];
  io.sockets.on('connection', function (socket) {
    setupChatSocket(socket, clients, pubClient, io);
  });
};

export default chatSocket

在setupChatSocket中执行this.subClient.psubscribe(this.channel + '*', onError)时,抛出错误:TypeError: this.subClient.psubscribe is not a function

原因分析

  1. 传递的客户端错误:你传给setupChatSocket的是pubClient而非subClient,如果this.subClient是从传入的客户端赋值来的,那它本质是发布客户端,没有psubscribe方法(只有订阅客户端才有订阅相关方法)。
  2. 客户端未正确初始化:如果this.subClient是自行创建的,可能没有完成连接,或者创建方式错误,导致不是有效的Redis订阅客户端实例。
  3. 适配器客户端复用冲突:Socket.io的Redis适配器已经在使用你创建的subClient做集群消息同步,直接复用它可能导致状态异常,无法执行额外的订阅操作。

解决步骤

步骤1:传递正确的subClient到处理函数

修改初始化代码,把subClient也传入chatSocket:

if (process.env.STATUS === 'development') {
  const pubClient = redis.createClient({
    port: process.env.REDIS_PORT,
    host: process.env.REDIS_HOST,
  });
  const subClient = pubClient.duplicate();

  io.adapter(redisAdapter({ pubClient, subClient }));

  // 同时传入pubClient和subClient
  chatSocket(io, pubClient, subClient);
}

更新chatSocket函数,接收并传递subClient给setupChatSocket:

import {setupChatSocket} from '../socket/serverEvents.js'

const chatSocket = function (io, pubClient, subClient) {
  let clients = JSON.parse(pubClient.get('clients'));
  if (!clients) clients = [];
  io.sockets.on('connection', function (socket) {
    setupChatSocket(socket, clients, pubClient, subClient, io);
  });
};

export default chatSocket

步骤2:确保subClient正确初始化并使用

在setupChatSocket中,若需要每个连接单独订阅,应创建独立的订阅客户端(避免复用适配器的客户端):

// 在setupChatSocket内部
export function setupChatSocket(socket, clients, pubClient, subClient, io) {
  // 为当前连接创建独立的订阅客户端
  const connectionSubClient = pubClient.duplicate();
  connectionSubClient.on('error', (err) => console.error('Redis订阅错误:', err));
  
  // 等待连接完成后再执行订阅
  connectionSubClient.connect().then(() => {
    const channel = '你的频道前缀';
    connectionSubClient.psubscribe(`${channel}*`, (err) => {
      if (err) console.error('订阅失败:', err);
    });

    // 处理订阅到的消息
    connectionSubClient.on('pmessage', (pattern, channel, message) => {
      socket.emit('message', message);
    });
  });

  // 连接断开时关闭订阅客户端,避免资源泄漏
  socket.on('disconnect', () => {
    connectionSubClient.quit();
  });

  // 其他socket业务逻辑...
}

步骤3:区分适配器客户端和业务订阅客户端

Socket.io的Redis适配器用的pub/sub客户端是做集群内Socket节点通信的,不要用它处理业务频道的订阅,避免干扰适配器正常工作。业务订阅应使用独立创建的Redis客户端实例。

额外注意事项

  • Redis客户端进入订阅模式后,只能执行subscribe/psubscribe/unsubscribe/punsubscribe这类订阅相关命令,不能再执行set/get等普通读写命令,业务读写操作需用单独的pubClient。
  • 务必在Socket连接断开时关闭对应订阅客户端,防止资源泄漏。

内容的提问来源于stack exchange,提问作者Hamoudeh Fouad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:15:36