ready事件不能直接用于判断重连成功,因其仅在首次连接完成认证、脚本加载及pub/sub同步后触发一次,后续重连不触发;应改用connect事件(每次tcp连接建立时触发)配合setimmediate延迟订阅。

为什么ready事件不能直接用于判断重连成功
ioredis 的 ready 事件只在首次连接建立时触发一次,后续断线重连成功后不会再次触发。如果你监听了 ready,却指望它在每次重连后都执行回调,那回调根本不会运行——这是最常踩的坑。
真正反映连接状态变化的是 connect 事件(每次 TCP 连接建立时触发)和 reconnecting 事件(开始重试时触发)。但要注意:connect 在首次连接和每次重连成功后都会触发,比 ready 更可靠。
-
ready:仅首次完成认证、加载脚本、同步完 pub/sub 状态后才触发,不适用于重连检测 -
connect:只要底层 socket 成功 connect 就触发,更及时、更通用 -
reconnecting:可用来做降级处理(比如暂停发布、标记服务不可用)
如何正确监听重连并恢复订阅
Redis 的 pub/sub 连接断开后,所有 channel 订阅会丢失,ioredis 不会自动重订 —— 即使它自己重连成功了。你必须手动在 connect 后重新调用 subscribe。
关键点是:不能在 connect 回调里直接 subscribe,因为此时客户端可能还没完全就绪(比如 auth 没完成)。稳妥做法是监听 ready + connect 组合,或更简单:用 on('connect', ...) + setTimeout(..., 0) 延迟执行订阅,确保事件循环让位。
- 推荐写法:监听
connect,然后用setImmediate(() => client.subscribe(...))或setTimeout(() => client.subscribe(...), 10) - 避免在
reconnecting中做任何订阅操作(此时连接尚未恢复) - 如果使用集群模式(
Redis.Cluster),需监听cluster:ready和cluster:connect,逻辑类似但事件名不同
配置 ioredis 重连策略避免雪崩
默认重连行为是指数退避(initialDelay=150ms,maxDelay=30s),但若没设 maxRetriesPerRequest,某些命令(如 publish)在网络抖动时可能无限等待重连,导致请求堆积。
必须显式配置以下两项:
-
retryStrategy(times):返回毫秒数(如Math.min(times * 50, 2000)),控制重试间隔 -
maxRetriesPerRequest:设为null(不限制)或一个较小数字(如3),防止 publish 阻塞 - 同时建议开启
enableOfflineQueue: false,避免断线期间 publish 积压,否则重连后一股脑发出去可能冲垮下游
示例初始化:
const Redis = require('ioredis');
const client = new Redis({
host: 'localhost',
port: 6379,
retryStrategy: (times) => Math.min(times * 50, 2000),
maxRetriesPerRequest: 3,
enableOfflineQueue: false,
});
监听失败后别漏掉 error 事件
ioredis 的 error 事件不会自动 throw,如果不监听,连接失败、认证错误、ECONNREFUSED 等问题会静默吞掉,导致你以为“一切正常”,实际早已断连。
必须监听并至少打日志,否则排查时会浪费大量时间:
- 监听
error并console.error或接入 logger,不要忽略 - 注意:部分错误(如
MaxRetriesPerRequestError)是重试耗尽后的最终报错,此时reconnecting已停止,应视为严重故障 - 如果使用
redis://URL 初始化,密码含特殊字符(如@、/)未编码,会直接抛URIError,这个不在error事件里,而是在构造时同步报错
订阅逻辑本身无异常捕获机制,出错全靠 error 事件兜底 —— 这一点很容易被忽略。











