Conversation
- 健康检查在 document.visibilityState 为 hidden 时直接视为健康,bridge 缺失仍返回 false - 重注入退避需持续健康满 60 秒才清零,探测不确定时不改变退避状态 - asset 查找失败缓存与 URL 查找结果挂在 window 上,跨重注入保留 Refs BigPizzaV3#2169 BigPizzaV3#2241 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
审查了一遍,思路和 Rust 侧实现我都认可,但当前版本不能合 —— 有一个阻断性问题。 阻断:产物与分片不一致本 PR 只改了 实测结果: 前端测试 269 pass / 1 fail,唯一失败的正是 这不是格式问题,改动会被静默抹掉。 我在本地跑了一次组装脚本验证:产物里的 需要改的位置把你的改动搬到分片
把产物一起提交。 Rust 侧:实现是对的,两点我都认同1. if (typeof bridge !== "function" || !health) return false; // 先判真丢桥接
if (document.visibilityState === "hidden") return true; // 再判隐藏页面重载导致桥接真丢失时仍返回 2. 退避需持续健康 60 秒才清零 —— 这条修的是真实缺陷。#2241 的退避实际上从未生效(我刚去核对了代码:重注入后紧接着的健康检查必然通过,因为 Some(true) => backoff.observe_healthy(Instant::now()),
None => {} // 探测不确定 → 不动状态
Some(false) => backoff.observe_unhealthy(),本地验证: 关于根因你的解释比我此前在 #2322 里的判断更准确。我当时看到「 一处确认
|
|
更正我上一条 review 里关于「产物与分片不一致」的批评 —— 那个批评不成立,是我搞错了。
而本 PR 的分支基点是 09-28 20:20( 我把「今天才有的规则」套到了「前天的提交」上,抱歉给你添了无用功。 实际需要的是 rebase,不是改代码分支落后 main 较多,而 main 上新增了分片体系。rebase 之后,你目前的改动会落在生成物上,需要把它们搬进对应的分片:
Rust 部分不受 rebase 影响,你已完成的测试结论仍然有效。 改完分片后跑一次: 把产物一起提交, 不变的部分Rust 侧的两处实现我依然认可,审查结论不变:
另外这个 rebase 需求对其他几个同样改 |
采纳 PR #2337 的思路,但把注入层改动落到分片源码而非产物(PR 只改了 `assets/inject/renderer-inject.js`,reviewer 已指出 assemble --check 报产物与 分片不一致;只改产物的话下一次 assemble 会把修复静默抹掉)。 根因(issue #2330 / #2169 / #2267 / #2201 同一链路) 窗口最小化后 Chromium 把后台定时器钳到约每分钟一次,注入脚本的 5s 心跳停摆, 而 `bridge_health_check_script` 只看 lastInjectionAt/lastSuccessAt/lastAttemptAt、 没有 visibilityState 判据,于是每轮探测都判失效;叠加 `Some(true) | None => backoff.reset()`(重注入后紧接的那次探测必然健康, `lastInjectionAt` 还在 5 秒窗口内)导致退避永远停在第一档。结果是每分钟重发 整份 616KB 脚本,连带全量 asset rescan。 改动 - `bridge.rs`:`bridge_health_check_script` 加 hidden 早返回。放在 bridge/health 存在性检查**之后**,保证页面重载后真丢桥时仍能修复。 - `launcher.rs`:`BridgeReinjectBackoff` 新增 `healthy_since`, `observe_healthy` / `observe_unhealthy`;持续健康满 `BRIDGE_REINJECT_BACKOFF_RESET_AFTER_SECS`(60s)才清零,探测不确定(None) 不改变退避状态。`browser_identity_changed` 的 reset 保留。 - `20-menu.js`(分片):`codexAppModuleFailures` 与新增的 `codexAppAssetUrlLookups` 挂到 window 跨重注入保留; `codexAppAssetUrlFromScriptText` 拆出扫描实现并加查找缓存(未命中同样缓存, 冷却期内不重复扫描)。 - 重组产物(assemble + --check 一致)。 测试 - Rust:新增 `reinject_backoff_resets_only_after_sustained_health` (立刻健康不清零 / 未满阈值不清零 / 不健康后重新计时 / 满阈值清零); `cargo test -p codex-plus-core --lib` 495 passed。 - 前端:`npm test` 312 passed。 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
感谢 @ViceEye 的修复。思路完全正确,三点都被采纳并落地——这个 PR 定位的根因(窗口隐藏被误判为桥接失效,叠加退避永远清零)正是 issue #2330 / #2169 / #2267 / #2201 的同一条链路。 已由提交 采纳的部分(与你的实现语义一致)
合入时改掉的一处(原 PR 无法直接合的阻断项) 顺带一提:你在注释里提到 |
审计当时的处置建议有两处被实测推翻、一处性质被更正,记下来: - **推翻 #2303 的「并发验证阻断项」**:默认并发 5 次全过(未复现 PR 描述的失败); 32 线程加压下 main 与 PR 分支会挂**同一个**用例 (upstream_request_returns_when_provider_accepts_but_never_sends_headers, 墙钟断言 assert!(started.elapsed() < 1s))。是既有 flake,不是 PR 引入。 真正阻断项是分支落后 34 提交。 另更正「保留 compaction: bool 单一标记路线」这条约束——加入原生透传后 compaction 语义已分裂,多字段反而更清晰。 - **推翻 #2313 的「范围过大需拆分」**:冲突只有 1 处且是陈旧基线 (main 的 04ab629 把 recovery_material 改成 2 参),解完整树全绿 1395/75/331。 不该因冲突要求改设计。 - **补充 #2333 的真实回归**(审计未发现):实测 model_catalog 测试红, 默认模型被静默换成 modelList 第一条。附教训:审查贡献者 PR 时必须单独验 「PR 自带测试是否覆盖整个 workspace」,只信 PR 描述的测试命令会漏跨 target 回归。 - 补记 #2309 两个阻断项的实测证据(版本号撞车、Err(_) 抵消退避修复)。 执行结果:#2366 已合入(ea82bc74);#2337 / #2371 由已落地提交覆盖后关闭; #2333 / #2309 回复要求修改;#2313 / #2303 回复可合但需先 rebase。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
问题
窗口最小化后,Chromium 会把后台定时器限制到大约每分钟一次(实测 5s 定时器被拉长到 22s 甚至更久)。
心跳停止更新 lastSuccessAt/lastAttemptAt,看门狗就判定桥接失效,每分钟重新注入一次 730KB 的脚本。
实测数据:
reinject_backoff_skipped为 0 次:修复桥接重注入导致的 CPU 空转与资源累积 #2241 的退避一次都没生效,因为刚注入完那次健康检查必然通过,退避被立即清零codexAppModuleFailures,后台 10 秒内发出 3032 个请求修改
bridge_health_check_script:document.visibilityState === "hidden"时直接返回健康;bridge 不存在时仍返回 false,页面重载后桥接确实丢失时照样修复BridgeReinjectBackoff:持续健康满 60 秒才清零(新增healthy_since);探测结果不确定时不改变状态;不健康时重新计时;应用实例更换时仍然立即清零renderer-inject.js:模块失败缓存和 asset URL 查找结果(包括未命中)挂在 window 上,跨重新注入保留,冷却 30 秒测试
cargo test -p codex-plus-core --lib launcher:新增持续健康测试,全部通过cdp_bridge健康检查:新增 hidden / hidden 且无 bridge / visible 三种情况,全部通过renderer-inject.test.ts:38 个用例全部通过#[cfg(windows)]代码以本 PR 的 Windows CI 为准不在本次范围内
旧实例的 listener 和 observer 泄漏(实测 window 上有 65 个 keydown)。修好这次的问题后重新注入会很少,之后单独处理。
Refs #2169 #2241