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

101 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3-14 Rust Web Tree Realtime WS Push 替代 SSE 轮询 v1
> 创建时间:2026-05-17
> 状态:`done`
> 关联 commit`57ec8322 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_socket``tokio::select!` 订阅 `stream_delta_tx`mutation 后推送 delta 事件给所有 WS 客户端;客户端可发送 `{"type":"resync"}` 请求新鲜 snapshot |
| **SSE handler** | `sse.rs` | 同时订阅 `block_delta_tx``stream_delta_tx`broadcast 可用时进入 push-only 模式(250ms heartbeat,无 Convex query),poll 降级为 60s 安全网 |
| **Call site updates** | 17 处 | `documents.rs``mindmap_api.rs``resource_trash.rs``tree.rs``hermes_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. 验证
```bash
# 编译 + 单测
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 指数退避