Skip to content

fix(inject): app-server patch 熔断不再被 provider 重试绕过,重试改指数退避 (issue #2256/#2255) - #2271

Merged
BigPizzaV3 merged 1 commit into
BigPizzaV3:mainfrom
dongyu23:codex/fix-2256-app-server-rescan-loop
Sep 22, 2026
Merged

BigPizzaV3 merged 1 commit into
BigPizzaV3:mainfrom
dongyu23:codex/fix-2256-app-server-rescan-loop

Conversation

@dongyu23

Copy link
Copy Markdown
Contributor

变更概述

修复 #2256 / #2255:Codex 桌面 26.911+ 改 bundle 哈希后,installAppServerModelRequestPatch 的 provider 重试路径绕过 maxMisses 熔断,失败退化为 250ms 无限重试,每轮全量重扫全部 app assets(实测每轮 fetch 275+ 个 app:// 资源),空闲时主进程 + 渲染进程持续各烧约 1 核 / 0.3-1 核,整机卡顿。

本 PR 仅修改 assets/inject/renderer-inject.js 中 issue 点名的两处缺陷,并为 apps/codex-plus-manager/src/renderer-inject.test.ts 补充回归测试,不改变 patch 正常安装路径与非 provider 模式的既有行为。

根因

  1. 熔断被 provider 路径绕过noteAppServerModelRequestPatchMisscodexRemoteSessionProviderPatchEnabled() 为真(relayMode pureApiofficial+mixApiKey)时提前 return,后面的 appServerModelRequestPatchMissCount >= maxMisses 熔断永远不可达,appServerModelRequestPatchDisabled 永不置位;scheduleAppServerModelRequestPatchRetry 固定 250ms、无退避、无上限。Codex 改 asset 命名后这层 patch 永远装不上,miss 变成无限重试,每轮经 loadAppServerRequestModulesappServerFallbackAssetUrls 全量重扫。
  2. fallback 名单硬编码旧版 bundle 哈希gwqc41kz|c1urrgy0|hsvsqcnf 在 26.911+ 上匹配不到任何文件(实测见验证),是死代码,且每个 Codex 大版本升级后都会变成这类过期名单。

loadCodexAppModule 路径在 issue #1960 已有 8 次上限 + 30s 冷却,但上述路径未对齐,循环回归。

修复内容

  • noteAppServerModelRequestPatchMiss:删除 provider 模式的提前 return,所有模式统一 miss 计数;达到 maxMisses(8) 后置位 disabled、清掉挂起的重试定时器并上报 model_app_server_request_patch_skipped;未熔断时调度重试。
  • scheduleAppServerModelRequestPatchRetry:重试间隔从固定 250ms 改为指数退避(250ms ×4 递增,30s 封顶);保留原有 provider 守卫,非 provider 模式行为与修复前完全一致(仍由白名单 tick 驱动,同样受熔断约束)。
  • 成功路径(patchedCount > 0)复位 miss 计数与退避间隔。
  • appServerFallbackAssetUrls:仅删除三个硬编码哈希(filter 正则与排序打分两处),稳定模块名模式(use-host-configapp-server-manager-signalsapp-initialapp-main 等)保持不变。
  • 新增 3 个回归测试(沿用既有 marketplace patch harness 模式):in-flight 去重、provider 路径 8 次熔断后彻底停手、成功后不重扫。

验证结果

单元/回归测试(Node 24.15.0,Windows 10 19045):

node --check assets/inject/renderer-inject.js
node --test apps/codex-plus-manager/src/renderer-inject.test.ts
  • 语法检查通过;renderer-inject.test.ts 37 项全部通过(含新增 3 项)。
  • 关键回归用例在旧代码下会观察到无限 sweep(40 轮调用 40 次扫描),新代码 8 轮封顶。

真实环境 A/B 验收(Windows 10 19045,OpenAI.Codex 26.915.4065.0 MSIX,Codex++ 经管理器正常启动流程,激活 relay 为 pureApi 模式,codexAppModelWhitelistUnlock 开启;CDP 9229 注入 fetch 计数探针,空闲会话页测量):

指标 修复前(baseline 构建) 修复后(本 PR 构建)
空闲 fetch 速率(20s 窗口) 29.3 次/秒 0 次/秒
重扫唯一 URL 293 个,100% app://,约每 10s 完整重扫一轮 0
patch 层行为 未安装,miss 无限循环 未安装,8 次熔断后永久静默
诊断序列 not_found 反复 not_found ×1 → skipped ×1 → 静默
第二窗口(30s)复核 依然 0 fetch
  • 删哈希无损性直接验证:在同一页面真实的 293 个 asset 清单上,新旧正则命中完全一致(11 = 11,差集为空),确认被删哈希在 26.915 上本就无匹配。
  • 量级说明:报告者实测 70-254 fetch/s,本验证探针只包裹 window.fetch(不含动态 import() 的网络层),故绝对值偏低,但重扫模式一致;修复后两个测量窗口均为零。

影响范围与限制

  • 非 provider 模式行为不变(重试调度仍仅限 provider 模式;两种模式熔断后都彻底停手,需页面重新加载才会再次尝试,与既有 loadCodexAppModule 熔断语义一致)。
  • 熔断是"有界失败后静默":若未来 Codex 版本连稳定模块名模式都改变,该层 patch 会装不上并熔断(CPU 不再空烧),剩余白名单层(Statsig / React state / response JSON patch)继续独立生效;恢复该层需要更新名单模式。
  • 未覆盖 macOS / Linux 实机采样;改动为纯 JS 注入层,平台无关。

回滚方案

回退本 PR 的单个提交即可:恢复提前 return 与固定 250ms 重试、还原两处正则中的哈希名单;不影响其他层。

关联:#2256 #2255(同根因的两份报告)

…izzaV3#2256/BigPizzaV3#2255)

- noteAppServerModelRequestPatchMiss 删除 provider 模式提前 return,两条路径统一
  miss 计数,maxMisses(8) 熔断对所有模式生效;熔断时清掉挂起的重试定时器。
- scheduleAppServerModelRequestPatchRetry 重试间隔从固定 250ms 改为指数退避
  (250ms ×4 递增,30s 封顶),补丁装成功后 miss 计数与退避间隔复位。
- appServerFallbackAssetUrls 删除硬编码的旧版 bundle 哈希(gwqc41kz 等),
  26.911+ 上本就匹配不到任何文件,属死代码;稳定模块名模式保持不变。
- 按 renderer-inject.test.ts 既有 harness 模式补 3 个回归测试。
@BigPizzaV3
BigPizzaV3 merged commit 545de2c into BigPizzaV3:main Sep 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants