Azure Functions+WebPubSub:如何获取群组内客户端连接数?
解决方案:判断Azure WebPubSub群组内唯一连接用户
要实现消息发送时判断自身是否为群组唯一在线用户,核心是维护全局共享的群组连接计数——因为Azure WebPubSub的单连接状态是私有,无法跨连接共享。以下是三种可行方案,按推荐优先级排序:
方案一:使用Azure WebPubSub服务端全局状态(无需额外服务)
利用WebPubSub内置的服务端全局状态功能,通过原子操作维护群组在线计数,避免并发冲突。
步骤1:安装WebPubSub管理SDK
在Azure Function项目根目录执行:
npm install @azure/web-pubsub
步骤2:在connected事件中递增计数
修改connected/index.js,用户加入群组后原子递增计数:
const { WebPubSubServiceClient } = require("@azure/web-pubsub"); module.exports = async function (context, req) { // 将用户加入group1 context.bindings.actions.push({ actionName: "addUserToGroup", userId: context.bindingData.connectionContext.userId, group: "group1" }); // 初始化服务端管理客户端 const serviceClient = new WebPubSubServiceClient( process.env.WebPubSubConnectionString, "chat" // 替换为你的hub名称 ); // 原子递增群组在线计数(不存在则初始化为1) await serviceClient.setState("group1_online_count", { value: 1, operation: "increment" }); context.res = { status: 200 }; };
步骤3:在disconnect事件中递减计数
修改disconnect/index.js,用户断开后原子递减计数:
const { WebPubSubServiceClient } = require("@azure/web-pubsub"); module.exports = async function (context, req) { const serviceClient = new WebPubSubServiceClient( process.env.WebPubSubConnectionString, "chat" ); // 原子递减群组在线计数 await serviceClient.setState("group1_online_count", { value: 1, operation: "decrement" }); context.res = { status: 200 }; };
步骤4:在message事件中判断是否为唯一用户
修改message/index.js,获取计数并判断:
const { WebPubSubServiceClient } = require("@azure/web-pubsub"); module.exports = async function (context, req) { const serviceClient = new WebPubSubServiceClient( process.env.WebPubSubConnectionString, "chat" ); // 获取群组在线计数 const stateRes = await serviceClient.getState("group1_online_count"); const onlineCount = parseInt(stateRes.value) || 0; const isOnlyUser = onlineCount === 1; // 处理消息并返回结果给群组 const response = { actionName: "sendToGroup", group: "group1", data: JSON.stringify({ content: req.body.data, isOnlyUser: isOnlyUser // 将判断结果传给客户端 }), dataType: "json" }; return response; };
配置注意事项
在Azure Function App的应用设置中添加WebPubSubConnectionString,值为你的WebPubSub服务的连接字符串(可在Azure Portal的WebPubSub资源中获取)。
方案二:使用Azure Redis Cache(适合高并发/多群组场景)
如果你的应用涉及多个群组或高并发连接,用Redis维护计数性能更优。
步骤1:安装Redis客户端
npm install redis
步骤2:修改connected事件
const { createClient } = require('redis'); module.exports = async function (context, req) { context.bindings.actions.push({ actionName: "addUserToGroup", userId: context.bindingData.connectionContext.userId, group: "group1" }); const redisClient = createClient({ url: process.env.RedisConnectionString }); await redisClient.connect(); await redisClient.incr('group1_online_count'); await redisClient.disconnect(); context.res = { status: 200 }; };
步骤3:修改disconnect事件
const { createClient } = require('redis'); module.exports = async function (context, req) { const redisClient = createClient({ url: process.env.RedisConnectionString }); await redisClient.connect(); await redisClient.decr('group1_online_count'); await redisClient.disconnect(); context.res = { status: 200 }; };
步骤4:修改message事件
const { createClient } = require('redis'); module.exports = async function (context, req) { const redisClient = createClient({ url: process.env.RedisConnectionString }); await redisClient.connect(); const onlineCount = parseInt(await redisClient.get('group1_online_count')) || 0; const isOnlyUser = onlineCount === 1; await redisClient.disconnect(); const response = { actionName: "sendToGroup", group: "group1", data: JSON.stringify({ content: req.body.data, isOnlyUser: isOnlyUser }), dataType: "json" }; return response; };
方案三:调用WebPubSub群组连接列表API(适合小群组)
直接调用管理API获取群组内所有连接,通过列表长度判断在线数,适合用户量少的场景(大群组会有性能开销)。
修改message/index.js:
const { WebPubSubServiceClient } = require("@azure/web-pubsub"); module.exports = async function (context, req) { const serviceClient = new WebPubSubServiceClient( process.env.WebPubSubConnectionString, "chat" ); // 获取群组内所有连接 const connections = []; for await (const conn of serviceClient.listGroupConnections("group1")) { connections.push(conn); } const isOnlyUser = connections.length === 1; // 消息处理逻辑... const response = { actionName: "sendToGroup", group: "group1", data: JSON.stringify({ content: req.body.data, isOnlyUser: isOnlyUser }), dataType: "json" }; return response; };
额外注意事项
- 异常断开处理:若客户端异常断开(如网络中断),
disconnect事件可能延迟触发,可设置WebPubSub的连接超时时间,或定期清理过期计数(Redis可设置键的过期时间,WebPubSub状态可添加TTL)。 - 权限控制:确保Function App的身份有调用WebPubSub管理API的权限(使用连接字符串时默认具备权限)。
内容的提问来源于stack exchange,提问作者gabrielsalvador
相关产品推荐
相关产品推荐

