Skip to content

fix(mobile): 限制首页过期快照的无界重拉 - #3729

Draft
sakiko-toyokawa wants to merge 1 commit into
makecindy:mainfrom
sakiko-toyokawa:fix/mobile-group-switch-anr
Draft

fix(mobile): 限制首页过期快照的无界重拉#3729
sakiko-toyokawa wants to merge 1 commit into
makecindy:mainfrom
sakiko-toyokawa:fix/mobile-group-switch-anr

Conversation

@sakiko-toyokawa

@sakiko-toyokawa sakiko-toyokawa commented Sep 1, 2026

Copy link
Copy Markdown

这次改了什么

摘要

修复 Mobile 首页设备会话全量快照在持续收到 sessions 推送时可能形成的无界尾随重拉。

v0.1.70 诊断报告已经确认:快照拉取期间 mutation epoch 一旦失效,原实现会立即再次执行 local-db:sessions:list,没有退避和次数上限。桌面端有活跃流式消息时,连续的 sessions:patched / usage 推送可能让这条路径反复执行,叠加分组切换的大量行重挂载后造成 Android JS/UI 线程压力、卡顿,甚至 ANR。

本 PR 不把该缺陷表述为已确认的唯一根因,只收敛代码已直接证明的无界 rerun 风险。

修补措施

  1. 每台设备的一轮 Home hydrate 最多执行 2 次尾随重拉,超过上限后保留已由增量推送维护的 store,不再继续全量拉取。
  2. 尾随重拉采用 100ms、200ms 指数退避,给连续推送合并窗口,避免完成后立即抢占 JS 线程。
  3. 增加 rerunScheduled 防护,同一 in-flight entry 只调度一次尾随任务。
  4. 延续现有 account generation 与 Home sync generation 栅栏;账号或设备范围已经切换时,延迟任务不会写回旧投影。
  5. 达到上限或放弃尾随拉取时恢复设备连接状态为 idle,避免 UI 永久停留在“同步中”。
  6. 更新 Home 源码契约测试,锁定次数上限、退避调度与 idle 收口。

变更类型

  • fix 缺陷修复

范围

Fixes #3728

  • 关联:v0.1.70 Android 分组切换卡死/闪退诊断报告;perf(mobile): 隔离 Device Link Peer 恢复与首页同步 #3590 引入的 mutation epoch rerun 路径。
  • 本 PR 包含:Mobile Home 会话快照尾随重拉的限次、退避、范围栅栏复用与状态收口。
  • 明确不包含:RNGH / RN / Reanimated 原生依赖回退;分组/非分组行 key 统一;folder 子行虚拟化;默认折叠策略。
  • 用户可见变化:持续推送与分组切换叠加时,不再允许后台全量列表重拉无限占用 JS 线程。
  • Breaking change:无。

UI 变化

  • 引用的设计规范:不涉及;没有视觉、交互或 UI 文案改动,只调整既有 Home 数据同步调度。

怎么验证的

自动验证

pnpm test:unit:related
结果:通过;apps/mobile related tests 通过。

pnpm --filter mobile run --if-present typecheck
结果:通过。

pnpm check:dco
结果:通过;1 个 commit 带匹配 author 的 Signed-off-by。

手工验证

尚未在报告中的 M2007J1SC(小米 10 青春版)或同等级 Android 真机上验证。该项必须在正式发布前完成。

未执行的验证

  • 未做 v0.1.70 灰度真机复现对照:当前环境没有报告设备与对应 production build。
  • 未执行 E1(Android 临时替换 plain View):本 PR 优先修复代码已证实的 perf(mobile): 隔离 Device Link Peer 恢复与首页同步 #3590 无界 rerun,不先改动手势栈或 runtime fingerprint。
  • 未做 Light/Dark 目检:没有 UI 样式或文案改动。

风险

风险分类

  • 其他:同步新鲜度与性能取舍。

影响与回滚

  • 影响范围:仅 Mobile Home 对远端设备会话列表的权威 hydrate 尾随重拉。
  • 新鲜度:达到 2 次上限时不应用已经过期的整表快照,保留实时增量推送已写入的状态;下一次 focus、foreground、下拉刷新或恢复触发仍可重新 hydrate。
  • 回滚方式:回滚本提交即可恢复原有立即、无上限 rerun 行为。
  • 原生层 / fingerprint / OTA:不涉及;只修改 TS 与测试,不改变 runtime fingerprint 输入。

正式发布前的下一步

  1. 用 v0.1.70 同一账号数据量,在报告设备 M2007J1SC 或同等级中低端 Android 上灰度构建。
  2. 同时保持桌面端活跃流式回合,分别在“对话归为一组”开启/关闭时反复切换“按项目分组”,记录卡顿、ANR 与 local-db:sessions:list 调用次数。
  3. 验收标准:不存在持续重拉;切换不再 ANR/闪退;列表最终可通过增量推送或下一次正常 hydrate 收敛。
  4. 若问题消失,说明 perf(mobile): 隔离 Device Link Peer 恢复与首页同步 #3590 的运行时压力贡献坐实,可进入正式发布评审。
  5. 若仍复现,立即执行诊断报告 E1:Android 诊断包临时把 SwipeableSessionRow 替换为 plain View,用于确认 Expo 57 / RN 0.86 / RNGH / Reanimated 栈下的单行挂载成本回归。
  6. 无论 E1 结果如何,后续治理分组切换的全量重挂载:稳定 grouped/mixed 行 key、将 folder 子行纳入虚拟化或调整默认折叠;该结构性改动单独 PR,并补真机性能基线。

提交前检查

  • 已 review 完整 diff;未发现 P0/P1。
  • commit 带 DCO 签名。
  • 未提交凭证、令牌或授权文件。
  • 已如实记录测试结果与未执行项。

当前为 Draft PR。请勿转 Ready、合并或进入正式发布,直到维护者查看本草稿并完成上述真机验证。

Signed-off-by: Codex <codex@users.noreply.github.com>
@sakiko-toyokawa
sakiko-toyokawa marked this pull request as ready for review September 1, 2026 07:59
@sakiko-toyokawa
sakiko-toyokawa requested a review from a team as a code owner September 1, 2026 07:59
@greptile-apps

greptile-apps Bot commented Sep 1, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 为 Mobile 首页的设备会话快照尾随重拉增加次数上限、指数退避和调度去重,并继续使用账号及 Home 同步 generation 栅栏限制延迟任务的作用域。

  • 每台设备最多执行两次尾随重拉,延迟依次为 100ms 和 200ms。
  • 达到上限时保留增量推送维护的 store,并将设备连接状态恢复为 idle。
  • 更新 Home 同步契约断言以覆盖新增常量和调度结构。

Confidence Score: 5/5

当前变更未发现阻塞合并的功能或安全故障,代码层面看起来可以安全合并。

未发现仍然存在的阻塞性故障。

Important Files Changed

Filename Overview
apps/mobile/app/devices/index.tsx 为会话快照失效后的尾随重拉加入计数上限、指数退避、单次调度保护和状态收口。
apps/mobile/src/tests/homeDesktopFirst.test.ts 更新 Home 同步源码契约断言,以反映新增的重拉上限、退避和 idle 状态处理。

Reviews (2): Last reviewed commit: "fix(mobile): bound stale home hydration ..." | Re-trigger Greptile

Comment on lines +519 to 523
expect(source).toContain("updateDeviceConnectionState(device.deviceId, 'idle');");
expect(source).toContain('setTimeout(() => {');
expect(source).toContain('homeDeviceSyncLimiterRef.current.run');
const hydrateSource = source.slice(
source.indexOf('const hydrateDeviceSessions = useCallback'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 重拉调度仅做源码断言

这些新增断言只验证限次、退避和 setTimeout 等源码片段存在,没有执行连续快照失效、计数传递和定时器调度;控制流回归后测试仍能通过,无法防止无界重拉问题再次出现。建议使用 fake timers 和可控的 hydrate 结果验证最多两次尾随重拉、100/200ms 退避以及最终 idle 收口。

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/mobile/src/__tests__/homeDesktopFirst.test.ts
Line: 519-523

Comment:
**重拉调度仅做源码断言**

这些新增断言只验证限次、退避和 `setTimeout` 等源码片段存在,没有执行连续快照失效、计数传递和定时器调度;控制流回归后测试仍能通过,无法防止无界重拉问题再次出现。建议使用 fake timers 和可控的 hydrate 结果验证最多两次尾随重拉、100/200ms 退避以及最终 idle 收口。

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@sakiko-toyokawa
sakiko-toyokawa marked this pull request as draft September 1, 2026 08:04
@DavidShenXD
DavidShenXD marked this pull request as ready for review September 1, 2026 10:15
@DavidShenXD
DavidShenXD marked this pull request as draft September 1, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants