Files
mnote/design/03-rust-web/done/3-14-rust-web-tree-realtime-ws-push-v1.md
T

5.1 KiB
Raw Blame History

3-14 Rust Web Tree Realtime WS Push 替代 SSE 轮询 v1

创建时间:2026-05-17 状态:done 关联 commit57ec8322 feat(mnote-web): replace SSE pollMs=1000 polling with WebSocket push for tree realtime events

前置设计稿:

  • design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md — SSE 事件流原始设计(本稿覆盖其 realtime transport 部分)
  • design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md — 3.4 Tree Realtime Live Cache checklist

1. 结论

/api/tree/events 的 SSE 轮询已替换为 WebSocket 推送 + SSE 降级。 所有 Convex mutation 完成后通过 stream_delta_tx broadcast channel 推送 deltaWS 客户端零 Convex 查询(idle 状态),SSE 客户端降级到 60s 安全网。Convex RSS 从 7.7G 降至正常水平,每页 idle 时 0 POST /api/query/min。

2. 问题

Convex backend RSS: 7.7G
POST /api/query/min: ~17/min
32h 内累计: 32K+ Convex queries
74% 来自 SSE pollMs=1000 轮询

SSE /api/tree/events?pollMs=1000 每 1 秒触发一次 load_stream_overview()execute_runtime_query_via_convex() → Convex POST /api/query。无论 workspace 状态是否变化,每个 cycle 都产生一次 Convex 查询。两个浏览器 tab 开同一 workspace 时,查询量翻倍。

3. 方案

3.1 Server 端

组件 文件 改动
Broadcast channel app.rs AppState 新增 stream_delta_tx: broadcast::Sender<Value>capacity 128
Command hook command_support.rs execute_runtime_command_via_convex_with_artifacts 签名从 (&AppConfig, ...) 改为 (&AppState, ...)mutation 成功后 stream_delta_tx.send({"kind":"command_committed", ...})
WS handler ws.rs handle_sockettokio::select! 订阅 stream_delta_txmutation 后推送 delta 事件给所有 WS 客户端;客户端可发送 {"type":"resync"} 请求新鲜 snapshot
SSE handler sse.rs 同时订阅 block_delta_txstream_delta_txbroadcast 可用时进入 push-only 模式(250ms heartbeat,无 Convex query),poll 降级为 60s 安全网
Call site updates 17 处 documents.rsmindmap_api.rsresource_trash.rstree.rshermes_tools/{artifact,block,page}.rs 全部 state.config()&state

3.2 Client 端

组件 文件 改动
Bootstrap config layout.rs JSON 中默认 transport: "convex-command-log-ws" + wsEndpoint: "/api/realtime/ws"
WS controller layout.rs (JS) TREE_LIVE_CONTROLLER_JS 扩展 startWithWebSocket():支持 snapshot / delta / resync / lagged-hint 事件
Auto-fallback layout.rs (JS) WS 2s 内无法连接时自动回退到 SSE

3.3 传输对比

SSE poll(旧) WS push(新)
Convex 查询 每 1s 一次,idle 不降 0(仅 mutation 后 push delta
延迟 max 1s 近实时(< 50ms
连接 HTTP long-poll 单 WebSocket
Convex RSS 影响 ~17 Q/min → 7.7G 0 Q/min idle
回退 WS 不可用时降级到 SSE(60s 安全网)

4. 对其他设计稿的影响

4.1 需更新口径的文档

文档 旧口径 新口径
3-3-rust-web-tree-realtime-event-stream-v1.md SSE /api/tree/events?pollMs=1000 是主 transport SSE 降级为 fallbackWS wss://.../api/realtime/ws 是主 transport
08-kernel-architecture-next-priority-review-and-checklist.md 3.4 中提到 /api/tree/events snapshot/delta/resync 覆盖 增加 WS push 验证项
AGENTS.md 3000 主壳接入 Rust Web /api/tree/events SSE consumer 更新为 WS consumerSSE 仅回退)
4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md transport 仍列 SSE 增加 WS transport 列
4-27-resource-lifecycle-command-cutover-v1.md SSE delta 路由描述 更新为 WS push delta

4.2 不受影响的文档

文档 原因
4-6-tree-command-protocol-cutover-stage2-v1.md 只涉及 command 协议,不涉及 transport
05-editor-mainline 系列 编辑器不依赖 tree transport
07-ai 系列 AI 工具不依赖 tree transport

5. 验证

# 编译 + 单测
cargo build --manifest-path rust/Cargo.toml -p mnote-web
cargo test --manifest-path rust/Cargo.toml -p mnote-web

# 浏览器 smoke
# 1. 打开 http://localhost:3000 → F12 Console
# 2. 检查:transport=convex-command-log-ws, status=connected
# 3. 等 2min → Convex 日志 0 新增 POST /api/query
# 4. 另一 tab 新建页面 → 首 tab 无需刷新,页面树/文件树自动更新

# 回归 smoke(双浏览器)
node scripts/task446-tree-rename-dual-browser-live-smoke.js
node scripts/task447-tree-move-order-dual-browser-live-smoke.js
node scripts/task448-tree-resync-recovery-dual-browser-smoke.js
node scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js

6. 后续

  • 完全移除 SSE poll 路径(当前仍保留 60s 安全网)
  • WS 连接池管理(多 tab 共享一条 WS)
  • Client 端 WS reconnect 指数退避