Skip to content

Keep the extension polling across a VoxClaw restart - #13

Merged
malpern merged 1 commit into
mainfrom
extension-poll-watchdog
Jul 25, 2026
Merged

Keep the extension polling across a VoxClaw restart#13
malpern merged 1 commit into
mainfrom
extension-poll-watchdog

Conversation

@malpern

@malpern malpern commented Jul 25, 2026

Copy link
Copy Markdown
Owner

The bug

The poll loop is a setInterval inside an MV3 service worker, which Chrome tears down after ~30s without extension API activity.

The success path calls chrome.action.setIcon/setTitle every second, which keeps the worker alive. The catch path — taken whenever VoxClaw is unreachable — made no chrome.* calls at all. So:

  1. VoxClaw quits or restarts → fetch throws → catch path, no API activity
  2. ~30s later the worker is torn down, and setInterval dies with it
  3. Nothing ever restarts it: startPolling only runs on install/startup/storage-change
  4. Ducking is dead until the browser is restarted

Observed directly while testing #10: after restarting VoxClaw, the listener answered 200 while the extension made zero requests across a 15s window, and stayed silent indefinitely.

This is pre-existing — it applies equally to the YouTube pausing that shipped before Spotify ducking — but it is much more visible now that the extension is actually installed and relied on.

The fix

Two independent guards, because the failure mode is completely silent:

  • chrome.action.setTitle in the catch path — the worker survives the outage instead of needing resurrection, and the toolbar now shows "VoxClaw (not running)". The API call is load-bearing beyond the title it sets; there's a comment saying so, since it looks removable.
  • A 30s chrome.alarms watchdog that restarts polling if the worker was torn down anyway (browser idle, crash, sleep). startPolling is already idempotent via its pollTimer guard. Adds the alarms permission.

Verification

Verified against a running browser (Dia, Chromium 150), reproducing the exact failure:

  1. Reloaded the extension and confirmed the new worker actually registered — service_worker_registration_info.version went 1.1.0 → 1.1.1, and serviceworkerevents gained alarms.onAlarm. (This check matters: a browser restart picks up new manifest permissions while still running the old worker script, which invalidated an earlier attempt at this test.)
  2. Quit VoxClaw, waited 70s with the listener down — past the ~30s teardown window that previously killed polling for good.
  3. Relaunched VoxClaw.

Result: 75 requests in 75 seconds, a steady 1 Hz resuming ~12s after the listener returned. Against the previous code the same sequence produced zero requests, permanently.

🤖 Generated with Claude Code

The poll loop lives in setInterval inside an MV3 service worker, which is torn
down after ~30s without extension API activity. The success path calls
chrome.action every second and keeps the worker alive, but the catch path —
taken whenever VoxClaw is unreachable — made no chrome.* calls at all. So
quitting VoxClaw killed the worker, the interval died with it, and nothing ever
restarted it: startPolling only ran on install/startup. Ducking stayed dead
until the browser itself was restarted.

Observed directly: after VoxClaw was restarted, the listener answered 200 while
the extension made zero requests over a 15s window, and stayed silent
indefinitely.

Two independent guards, since the failure is silent:
- chrome.action.setTitle in the catch path, so the worker survives an outage
  rather than needing resurrection. It also surfaces the state in the toolbar.
- A 30s alarm that restarts polling if the worker was torn down anyway.
  startPolling is already idempotent via its pollTimer guard.

NOT YET VERIFIED against a running browser: loading new worker code requires
clicking Reload on the extensions page, and a browser restart is not sufficient
(confirmed by changing POLL_INTERVAL_MS to 2000, restarting Dia, and still
measuring a 1s poll interval — the old script kept running). Dia is currently
unable to open a window for that click.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@malpern
malpern merged commit 7d3de9a into main Jul 25, 2026
2 checks passed
@malpern
malpern deleted the extension-poll-watchdog branch July 25, 2026 20:46
@malpern malpern mentioned this pull request Jul 25, 2026
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.

1 participant