用户点退出,自己的页面里头像消失了,其他五个人看到的在线人数还是 6,刷新才变 5,数据库 room_member 有一行 updated_at 停在 3 小时前。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
DELETE FROM room_member WHERE room_id = ? AND last_seen < NOW() - INTERVAL 90 SECOND;
退出只发了 leave 消息,客户端随即断开,服务端在 onclose 里没做清理,以为人走了其实 socket 还挂着。半开连接不会触发 onclose,要等心跳超时才能发现。这一点先确认清楚,后面就不用反复试。
「房间成员状态」这类改动最怕改一半,回滚脚本先准备好,再动生产。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。
改完隔一天再看一次,当场正常不代表能稳住。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。
具体做法是,onclose 和 leave 走同一个清理函数 两条路都删;成员表加 last_seen 字段 心跳时更新;定时任务扫 last_seen 超过 90 秒的成员 主动剔除并广播;前端只按 member_leave 事件更新列表 别只信本地状态。
改完照着核一遍,退出后其他客户端 1 秒内收到 member_leave 在线人数从 6 变 5 不用刷新。
