const keys = [...room.members.keys()];
for (const k of keys) {
  const c = room.members.get(k);
  if (c) c.send(payload);
}

三人房间发一条 system 消息,A 和 C 收到,B 没有,服务端日志显示 broadcast 循环只跑了两轮,房间人数打印出来是 3。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:广播前先踢掉超时连接,代码在遍历 Map 的过程中直接 delete,迭代器跳过了一个元素。房间对象在多处被并发修改,遍历时拿到的是改动中的快照。

围绕「广播漏发」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。监控和日志的时间要对上,时区不一致会多绕很大一圈。

临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

处理上按这个顺序:遍历前把成员 key 复制成数组 用副本做循环;失效连接先收集 循环结束再统一删;单个成员发送失败单独捕获 不要中断后面的;补一个发送计数 和房间人数对比。

确认没问题再收工,连发 20 条广播 三个客户端收到的条数完全一致 服务端计数和房间人数对得上。

作者 9823189