Skip to content

fix: 冷启动后台卡死导致代理失效与弹窗空白 (#276)#327

Open
hughcube wants to merge 2 commits into
zero-peak:masterfrom
hughcube:bugfix/popup-hang-on-cold-start-276
Open

fix: 冷启动后台卡死导致代理失效与弹窗空白 (#276)#327
hughcube wants to merge 2 commits into
zero-peak:masterfrom
hughcube:bugfix/popup-hang-on-cold-start-276

Conversation

@hughcube

Copy link
Copy Markdown

问题 (Closes #276)

在 Chrome 刚打开(冷启动)时,扩展经常只剩一个工具栏图标:弹窗加载不出来、点击无响应,整个代理也一并失效,必须手动在 chrome://extensions 里 reload 插件才能恢复。

根因

后台 service worker 的 Options#init(omega-target/src/options.coffee)在应用情景模式(设置 chrome.proxy.settings)之前,会先 await 一次 state(IndexedDB)读取。在 MV3 service worker 冷启动时,这次 IndexedDB 读取有时会永久挂起,于是:

  • options.ready 永不 resolve → applyProfile 从不执行 → 代理从未被设置(整体失效);
  • 后台也永远不回应 popup 的 getState 消息 → 弹窗一直空白("只剩图标")

两个症状同源,都卡在这次挂起的存储读取上。

修复

1. 后台根治 (omega-target/src/options.coffee)
给启动流程加一道超时保险:若 loadOptions + 应用初始情景在限定时间(默认 5s)内没完成,就用配置的「启动情景」或兜底情景强制把代理设上,并让 options.ready resolve。这样任何启动期存储读取挂起都不会再让代理和弹窗一起卡死。

2. 弹窗自愈 (omega-target-chromium-extension/src/coffee/omega_target_web.coffee)
callBackgroundchrome.runtime.lastError(service worker 尚未唤醒/就绪)时做有限次重试与退避,并让 state() 的 promise 正确传播拒绝,避免一次消息失败就让弹窗永久挂起。

测试

新增 omega-target/test/options_startup.coffee:用一个"读取永不返回"的 state 确定性模拟冷启动挂起,断言修复后仍能 applyProfileready 会 settle(无需浏览器/网络/凭据即可复现并验证)。

副作用

正常启动只需几十~几百毫秒,远不到超时阈值,超时分支不会触发,行为与改前一致。仅在"启动卡死"这一异常场景才介入:先用启动/兜底情景保证浏览器可用,待挂起的读取最终返回后原流程会再应用真正的情景(chrome.proxy.settings 幂等,最终一致)。

hughcube added 2 commits June 10, 2026 17:54
On Manifest V3 the background service worker may still be asleep or
initializing when the popup is opened right after a browser restart.
The popup's first getState message then fails with
chrome.runtime.lastError and no response is delivered. The
omegaTarget.state() wrapper only resolved its deferred inside .then(),
with no rejection handler, so a single missed response left the
deferred unsettled forever: the popup stayed blank, showing only the
toolbar icon, with no way to recover except reloading the extension.

- Retry callBackground() a few times with a small backoff when
  sendMessage fails with chrome.runtime.lastError, to ride out the
  service-worker wake-up race.
- Propagate rejections in omegaTarget.state() so a permanently failed
  call rejects the promise instead of hanging silently.

Closes zero-peak#276
…o-peak#276)

On a service-worker cold start, Options#init awaited a state (IndexedDB)
read BEFORE applying a profile. When that read stalls (which happens on
cold starts), options.ready never resolved: applyProfile never ran so the
proxy was never configured, and the popup never got a getState reply so it
stayed blank ("only an icon"), until the extension was reloaded by hand.

Wrap startup in a timeout. If loadOptions plus applying the initial profile
does not finish in time, fall back to applying the configured startup
profile (or the fallback profile) so the proxy gets set and ready resolves.
Add a deterministic regression test that simulates a stalling state read.
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.

在chrome刚打开时 很容易出现页面加载不出来的问题 这时点击任何地方都是无响应 导致无法使用

1 participant