PC 端向安卓端一次性/全量下发消息,导致安卓对话重启(渲染不过来)
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
### 问题描述
PC 端 Cindy 推送到安卓端时,消息被**整段会话一次性下发**。安卓端(vivo V2405A)渲染不过来时对话界面会重启(重新走全量快照同步)。链路走 `device-link.cindy.app` 云端 WebSocket 中转。
### 环境版本与再现日期
- Windows 桌面端:0.1.28 → 0.1.45(热更新,见下方更新日历)
- 安卓端:vivo V2405A,peer id `aece6cc0`
- 日志:桌面端 `CindyGlobal\logs\main-*.log`
| 日期 | 桌面版本(更新日) |
|---|---|
| 08-03 ~ 08-05 21:03 | 0.1.28 |
| 08-05 21:03 + | 0.1.31 |
| 08-06 14:27 + | 0.1.33 |
| 08-07 18:31 + | 0.1.36 |
| 08-08 20:05 + | 0.1.37 |
| 08-09 18:03 + | 0.1.38 |
| 08-10 22:09 + | 0.1.43 |
| 08-11 17:42 + | 0.1.44 |
| 08-12 19:58 + | 0.1.45 |
### 日志证据
1. **安卓每次重连即发起一组全量 RPC**,PC 回灌整段会话:
`local-db:messages:list`、`local-db:sessions:get`、`maker:get-capabilities`、`maker:get-pending-interactions`、`maker:input:get-projection`、`maker:list-active`、`fs:stat-path ...`
2. **turn 结束时事件批量冲刷,发送被拒**:
```
maker:event batch flush to aece6cc0: send rejected, dropped 16/1/22/43/21/15/20/64/12/11 event(s)
```
(2026-08-11 09:10:38 ~ 09:10:39,2 秒内约 225 个事件被丢弃)
3. **可靠传输缓冲饱和,触发链路复位**:
```
reliable transport buffer is full for peer aece6cc0
reliable transport ACK timeout for aece6cc0 seq=...; resetting peer link
dropped N discardable pending frame(s) (best-effort push / transport-skip) ... to make room for invoke-result
```
4. **链路复位 → 安卓重连 → 再次拉全量快照 → 再次一股脑灌**,形成"对话重启"循环。
### 逐日计数(main 日志按天统计)
| 日期 | buffer 满 | 丢帧批次 | ACK 超时 | 链路重建 | DEVICE_OFFLINE |
|---|---|---|---|---|---|
| 08-05 | 869 | 27 | 7 | 95 | 25 |
| 08-06 | 5432 | 20 | 5 | 93 | 10 |
| 08-07 | 9476 | 33 | 14 | 93 | 21 |
| 08-08 | 90 | 4 | 3 | 20 | 2 |
| 08-09 | 2787 | 4 | 3 | 34 | 2 |
| 08-10 | 0 | 3 | 0 | 13 | 3 |
| 08-11 | 10 | 23 | 11 | 116 | 24 |
| 08-12 | 0 | 1 | 0 | 4 | 1 |
| 08-13 | 0 | 1 | 0 | 19 | 25 |
#### 补充说明(2026-08-13,对应 bot 的核实要求)
- **buffer-full 已基本消失**:0.1.36(08-07)之后反复出现的 `reliable transport buffer is full` 已由峰值 9476 降至 0~10 次/天,说明相关修复(PR #1375 一带)已生效。
- **症状仍在的残余项**(0.1.43/0.1.44/0.1.45 上依然复现):
- `maker:event batch flush ... dropped N event(s)`:08-11 09:10 仍在 2 秒内丢 ~225 个;
- 链路重建 08-11 达到 116 次/天,08-13 半天 19 次;
- `DEVICE_OFFLINE` 与收尾重连在 08-11/08-13 反而升高,方向上与 Android 端渲染滞后/被卡死后的超时重连一致。
- 即:**最差的"缓冲爆表拖垮链路"已修复;但"整段会话一次性 fan-out 导致安卓渲染不过来进而被超时踢下线"这条路径尚未根除**——这正是本 issue 期望剩余部分。
### 期望修复
1. **分页/滚动窗口下发**:不要一次性回灌整段会话;`messages:list` 等应支持分页,并做增量合并。
2. **基于 ACK 进度的流量控制**:对端被压垮时应"暂停下发 + 排队",而不是直接丢弃 + 链路复位 + 重连重传(当前兜底策略会放大问题)。
3. **区分大 payload 与流式 event 的拥塞策略**:`messages:list` 等大响应与增量事件分开排队,避免互相挤占。
4. **降低链路抖动敏感度**:对 `ENOTFOUND / 401 / DEVICE_OFFLINE` 期间的事件做持久化批量补齐,而不是重连后甩给客户端整段重建。
Contributor guide
Research direction
Start with the desktop logs in CindyGlobal\logs\main-*.log and trace the messages:list, local-db:sessions:get, and maker:event batch flush entry points across the device-link.cindy.app WebSocket path. Compare reconnect behavior with the listed reliable transport buffer and ACK timeout events. Done means large snapshots are paged or incrementally merged, backpressure queues data instead of dropping it, and Android no longer enters the reconnect/full-snapshot loop.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design, distributed-systems, mobile-dev, networking
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100