IM · WuKongIM 长连接与会话列表策略
创建: 2026-07-25 · 2026-07-31 归入学习笔记(原理说明,非开发待办)
状态:现阶段共识(策略 A)· 摘要已并入 13-IM「连接与会话列表约定」
关联:ADR-025 · 欠账 迭代主线 §2.0
App:my-tandem-travel·pages/chat/chat.vue·utils/im/session.js·utils/im/conversation-cache.js
TL;DR
- WuKongIM 是 WebSocket 长连接 + 心跳,不是「发完就断」的短请求。
- 本项目现状 = 策略 A:进消息 Tab 才连,连上后保持。实时性要求不高,现阶段够用;1000 在线量级对 WuKongIM 通常不是瓶颈。
- 「重进消息 Tab 后最后一条/未读被清空」不是重连本身清了消息,而是
GET /conversations/list在 webhook 未回写时返回lastMessagePreview=null / unreadCount=0,前端整表覆盖把内存里的实时摘要冲掉了。详情页历史走 WuKongmessagesync,所以点进去内容还在。 - 前端已用 本地摘要缓存 + 合并策略 兜底;业务库摘要仍依赖 webhook(U1),运维侧确认重启后才是权威源。
1. 连接模型是什么
App ──WebSocket(长连接)──► WuKongIM(收发 / 心跳 / 离线存储)
App ──REST /api/im/*────► Spring(Token / 好友 / 会话元数据 / 已读清零)
WuKongIM ──webhook──────► Spring(回写 last_message_* / unread_count,不存正文)| 概念 | 说明 |
|---|---|
| 长连接 | 连上后心跳维持(wk.yaml heartbeat_interval: 30),直到断网 / 杀进程 / disconnect / 被踢 |
| 在线推送 | 已连接时 SDK chatManager.addMessageListener 收包 → uni.$emit('im:message') |
| 离线历史 | 未连接期间消息存在 WuKong;再连后靠 channel/messagesync 拉 |
| 会话列表摘要 | 理想情况来自业务库(webhook);正文永不进 Spring |
配置参考(理论值,实战受内存限制):
websocket.max_conn: 100000- compose 里 WuKongIM 内存约 300M → 真瓶颈往往是内存 / FD,不是「注册用户数」
2. 本项目当前行为(对照联调现象)
| 阶段 | 行为 | 体验 |
|---|---|---|
| 从未点过「消息」 | 不 ensureConnected | 收不到实时推送 |
| 进入消息 Tab | onShow → ensureConnected + 拉 REST 列表 | 开始实时 |
| 连上后切到「我的」等 Tab | 连接保持 | 仍可 toast / 红点(已验证) |
| 杀进程后再进 | 需再次进消息 Tab 才连 | 符合策略 A |
产品取舍:不要求「人在任意 Tab 都秒推」;要求「点开消息 Tab 能看到最新摘要 + 进详情能看历史」。
3. 三种策略对比
| 策略 | 做法 | 体验 | 连接压力 | 复杂度 | 本阶段 |
|---|---|---|---|---|---|
| A. 懒连接 + 连上保持 | 进消息才连,不主动 idle 断 | 中 | 中(活跃用户) | 低 | ✅ 采用 |
| B. 启动常驻 | App 启动 / 登录后就连 | 最好 | 最高 | 低 | 用户过万或客诉多再议 |
| C. 懒连接 + 空闲断开 | 离开消息相关页 N 分钟 disconnect,再进 sync | 略差 | 最低 | 中 | 连接告警后再议 |
业界常见:前台长连 + 后台系统推送(微信订阅消息 / APNs 等)。我们未接系统推送前,A 是合理默认。
4. 「重进 Tab 摘要被清空」根因与修复
根因链
- 实时消息更新的是 前端内存(及后来加的本地缓存)
onShow/ 重连成功后调用loadConversations(true)→GET /api/im/conversations/list- 若 WuKong webhook 未生效,库里
last_message_preview/unread_count仍是 null / 0 - 旧逻辑:整表替换
conversations = apiList→ UI 预览与未读被冲空 - 详情页走 WuKong sync → 聊天内容仍在(与列表摘要无关)
这与「重新连接 IM」相关,但是 重连触发了 REST 刷新,不是 WS 把历史删了。
修复(App)
utils/im/conversation-cache.js:按用户缓存会话摘要loadConversations(true):mergeConversationLists(api, local)- API 有预览 → 以 API 为主(webhook 正常时)
- API 无预览 → 保留本地/缓存 预览与未读
- 实时更新 / 标已读时同步写缓存
仍建议运维确认(权威源)
bash
# 服务器确认 wk.yaml webhook.enabled=true 且指向 tour-mate-app
# 改过配置后需:./deploy.sh restart wukongim
# 发一条消息后查 im_conversations.last_message_preview 是否非空前端兜底保证「webhook 挂了也能用」;webhook 通了之后列表以服务端为准更一致(多端)。
5. 容量粗估(回答「1000 用户压力」)
- 在线连接数 ≈ 同时开着 App 且已进过消息 Tab 的用户,不是注册用户总数。
- 例:DAU 1000、同时在线 10%、其中一半进过消息 → 约 50 条长连接,可忽略。
- 单机 WuKongIM 配置
max_conn很大;小机器先看 RSS / 打开文件数。 - 优化顺序:监控 → 再考虑策略 C;不要过早为省连接牺牲体验。
6. 何时升级策略
| 触发 | 动作 |
|---|---|
| 客诉「不在消息页完全收不到、红点也不准」且 webhook 已通 | 考虑策略 B,或未读 REST 轮询 |
| 在线连接 / 内存告警 | 策略 C(idle disconnect) |
| 需要杀进程后仍触达 | 接微信订阅消息 / 厂商推送(另开专题) |
7. 相关代码路标
| 端 | 路径 |
|---|---|
| 懒连接 | App utils/im/session.js · pages/chat/chat.vue onShow |
| 收消息 | App utils/im/wukong-client.js → chatManager.addMessageListener |
| 列表合并 | App utils/im/conversation-cache.js |
| 会话 REST | Spring ImConversationController |
| 已读清零 | PUT /api/im/conversations/{id}/read(U2) |
| Webhook | POST /api/im/webhook/wukong · wk.yaml webhook 段 |
8. 共识(可勾选)
- [x] 现阶段锁定 策略 A,不改为启动常驻
- [x] 列表摘要:本地缓存兜底 + webhook 权威(运维确认);未读仅「点进会话」清零(
readAt) - [x] 图片 / 语音发送:上传
scene=chat→MessageImage(2) / 自定义 Voice(3);位置仍未开放 - [ ] 连接数监控 / idle 断开:过后再开
- [ ] 系统级推送:另开专题
- [ ] 位置消息 / 多图 / 视频:延后
- [ ] 聊天内容安全真实挂钩:延后(M2)