Files
cc-web/.planning/2026-09-13-session-switch-diagnosis/findings.md
2026-09-13 23:59:27 +08:00

3.5 KiB
Raw Blame History

切换对话诊断发现

当前已知

  • 会话文件仍包含用户消息,暂未发现数据层删除。
  • 切换通过 WebSocket load_session 请求完成,刷新会创建新连接。
  • 服务端日志存在大量心跳终止和断线重连记录。
  • 前端同时处理会话缓存、加载请求代次、历史分页、运行态恢复和滚动位置。

可复核证据

  • server.js:5656-5658 普通加载只发送最近 INITIAL_HISTORY_COUNT = 12 条; server.js:10890-10907 同时发送完整 historyTotal、historyCursor、 historyBaseIndex 和 historyTruncated,普通大历史请求可以出现 messages=12, historyTotal=99, historyCursor=87, historyPending=false。
  • 原逻辑 public/app.js:2607-2611 用 !payload.historyPending 推导 complete,因此上述部分快照会被标成完整;随后 session_info → cacheSessionSnapshot → getSessionCacheDisposition → showCachedSession 可在 A → B → A 时绕过服务端重新加载。
  • 修复后 normalizeSessionSnapshot 和 isCompleteSessionSnapshot 共同要求 游标归零、未截断、未等待分片且缓冲数覆盖总数;缓存写入和读取都复用同一 谓词。历史分片按 historyBaseIndex 合并,最后一页才转换为完整缓存。
  • 部分快照现在进入独立 sessionHistoryBuffers,仅供后续 load_history_page 合并;getSessionCacheDisposition 永远不会把它当作可展示缓存。分页游标归 零后才调用 cacheSessionSnapshot,因此 A → B → A 不会复用半截历史。
  • logs/process.log 中存在 ws_heartbeat_terminate,例如 2026-09-13T07:30:03.445Z,missedPongs=4、lastActivityAgeMs=150471; server.js:2216-2221 的 markWsActivity 已会把 isAlive 恢复为 true, 因此该记录更符合浏览器/反向代理长期未返回 pong 的半断连接,而不是服务端 漏置位。
  • 客户端原先只在 onclose 触发重连;现增加 WS_CLIENT_HEARTBEAT_INTERVAL_MS (15 秒)与 WS_CLIENT_HEARTBEAT_TIMEOUT_MS(10 秒),通过 client_heartbeat → client_heartbeat_ack 主动识别浏览器仍显示 OPEN 的半断, 再复用现有 onclose 流程重放切换请求。

问题边界

  • 会话文件未发现消息被删除;气泡消失的直接原因是前端错误缓存/重绘, 不是数据库或服务端历史丢失。
  • WebSocket 处于浏览器 OPEN 但链路半断时,send(load_session) 可能无效; 刷新页面会强制新建连接。现在客户端最多约 25 秒主动发现并重连,真实反向 代理是否丢弃控制帧仍需浏览器现场或代理配置验证。
  • 未重启现有 ccweb,因为当前会话列表中还有另一个 running 对话;源码修复 需在安全窗口重启后才会进入线上进程。

2026-09-13 新增线上证据

  • 用户截图中的 Unknown type: client_heartbeat 证实线上 PM2 仍运行未包含 client_heartbeat 分支的旧 server.js;前端先部署心跳会被旧服务端当作业务 错误,并触发连接重连循环。
  • mcp__ccweb__ccweb_list_conversations(status=running) 显示当前会话之外仍有 一个 running 会话,按项目运维约定本轮不能重启 PM2。
  • 已在前端加入 auth_result.features.clientHeartbeat 能力闸门:旧服务端不声明 时不发送心跳;即使旧页面已发送并收到 Unknown type,也会静默停用心跳,不再 将协议探测错误显示到聊天区。新版服务端已声明该能力,安全重启后可恢复探测。