如何查询Redis PubSub指定主题的订阅数量(graphql-redis-subscriptions)
问题根因
你写的代码返回0是因为对graphql-redis-subscriptions的内部实现和Redis Pub/Sub的机制存在误解:
getPublisher()返回的是专门用于发送消息的Redis连接,这个连接从不会执行SUBSCRIBE命令,本身不会绑定任何消息监听器,调用它的listenerCount永远返回0。getSubscriber()返回的订阅端Redis客户端,不会把你传入的业务监听器(也就是代码里的aListener)直接绑定到对应channel的事件上。graphql-redis-subscriptions会在内存里单独维护一层业务监听器的映射表,每个channel只会给Redis客户端绑定1个内部转发回调,用来把收到的Redis消息分发给内存里存的所有业务监听器。就算你等订阅流程完全走完再调用listenerCount,拿到的值要么是0(该channel无任何订阅)要么是1(该channel至少有1个业务订阅),根本反映不了真实的业务监听器数量。- 你是在
await pubSub.subscribe(...)之后立刻同步调用listenerCount,但graphql-redis-subscriptions内部向Redis发送SUBSCRIBE命令、绑定内部监听器的流程存在异步时序差,调用时监听器还没完成注册,自然返回0。
正确统计方式
根据你需要的统计维度选择对应方案:
统计当前服务进程内的订阅数
如果是单实例部署,只需要统计当前Node进程里指定topic下的业务监听器数量,可以直接读取实例内部维护的订阅映射表(注意这个属性是内部实现,升级依赖版本时需要留意兼容性):
const topicSubMap = pubSub.subscriptions.get('someTopic') const localListenerCount = topicSubMap ? topicSubMap.all.size : 0 console.log('当前实例上该topic的订阅数:', localListenerCount)
统计全局维度的订阅数
如果是多实例部署,分两种场景:
- 统计监听该topic的服务实例数量
直接用Redis原生提供的PUBSUB命令查询服务端记录的channel订阅数即可,注意这个值的统计维度是Redis连接数,每个服务实例只要对某个topic存在至少1个业务订阅,就会占用1个订阅连接:const [, instanceCount] = await pubSub.getSubscriber().pubsub('NUMSUB', 'someTopic') console.log('监听该topic的服务实例总数:', instanceCount) - 统计全量终端用户的订阅总数
Redis本身不记录业务维度的订阅数,你需要自己维护全局计数器:每次有客户端成功建立该topic的订阅时,给Redis中对应的计数key执行+1操作;每次客户端断开连接、主动取消订阅时执行-1操作,同时给计数key设置合理的过期时间做兜底,避免异常断连导致计数不准。
内容的提问来源于stack exchange,提问作者Supperhero
相关产品推荐
相关产品推荐

