Skip to content

Bound the browser policy refresh so a wedged browser can't stall an update - #9423

Open
VykosMolt wants to merge 1 commit into
omacom:quattrofrom
VykosMolt:fix/browser-refresh-timeout-8212
Open

Bound the browser policy refresh so a wedged browser can't stall an update#9423
VykosMolt wants to merge 1 commit into
omacom:quattrofrom
VykosMolt:fix/browser-refresh-timeout-8212

Conversation

@VykosMolt

Copy link
Copy Markdown

refresh_running_browser in bin/omarchy-theme-set-browser runs the browser's policy handoff in the foreground with nothing bounding it:

"$command" --refresh-platform-policy --no-startup-window &>/dev/null

A browser that does not return therefore holds up omarchy-theme-set-browser, the theme change, the migration that called it, and the update running that migration. #8212 reports an hour-long hang at migration 1787481315; a second report on the same issue has Chromium taking 68 seconds at 1787515927.

That second case matters for scoping. It was a correctly detected running Chromium, so this is not only the brave/brave-origin detection mix-up — #8258 fixes that detection, and this would still hang. The two are complementary.

The refresh only asks an already-running browser to re-read the policy it was just handed. The file on disk is what the next launch reads either way, so losing the refresh costs a running browser its new colour until it restarts, while blocking on it costs the whole update.

Why -k and not a plain timeout. A browser that ignores SIGTERM leaves plain timeout waiting exactly as long as the process it was meant to bound:

timeout 2s       <TERM-ignoring child>   returned after 20s
timeout -k 1s 2s <same child>            returned after 3s

Plain timeout does clean up the process tree when the child cooperates — parent and children all die, since it signals the group — it just cannot help when the child does not.

The refresh keeps its existing exit contract. It never fed the command's status, which stays owned by the policy write.

Testing

New test/shell.d/browser-policy-refresh-test.sh, hermetic: stub browsers on a private PATH, and a stub pgrep that answers only for the browsers the fixture declares running, so a browser actually installed on the machine running the suite is never probed or launched. It covers a browser that refreshes cleanly, one that never returns and ignores TERM, that later browsers are still refreshed after an earlier one hangs, that a timed-out refresh does not change the exit status, that no process is left behind, and that a failed policy write still fails the command.

Against unpatched quattro it fails in 30s on "converges when a browser refresh never returns". The harness bounds its own invocation so a regression fails rather than hanging the suite, and its cleanup kills the stub tree so a failure leaves nothing behind.

./test/shell — 218 of 222 files pass; the four failures (config-test, runtime-smoke-test, snapper-test, unowned-system-paths-test) fail identically on unmodified quattro on this machine. shellcheck reports the same SC1091/SC2086 counts before and after — no new findings. bash -n and git diff --check clean.

Fixes #8212

…pdate

refresh_running_browser ran the browser's --refresh-platform-policy handoff in
the foreground with nothing bounding it. A browser that does not return then
holds up omarchy-theme-set-browser, the theme change, the migration that called
it, and the update running that migration — reported as an hour-long hang at
migration 1787481315, and again with Chromium taking 68 seconds at 1787515927.

The refresh only asks an already-running browser to re-read the policy it was
just handed. The file on disk is what the next launch reads either way, so
losing the refresh costs a running browser its new colour until it restarts,
while blocking on it costs the whole update.

Use `timeout -k`, not a plain timeout. A browser that ignores TERM leaves plain
`timeout` waiting exactly as long as the process it was meant to bound:

  timeout 2s       <TERM-ignoring child>  returned after 20s
  timeout -k 1s 2s <same child>           returned after 3s

The refresh keeps its existing exit contract: it never fed the command's status,
which stays owned by the policy write.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

omarchy-update hangs at migration 1787481315 when brave-origin is the daily browser (theme-set-browser blocks on brave that never exits)

1 participant