Skip to content

Fix bug with worker running after closing the page - #480

Open
cupicmarko wants to merge 1 commit into
mainfrom
fix/pause-worker
Open

Fix bug with worker running after closing the page#480
cupicmarko wants to merge 1 commit into
mainfrom
fix/pause-worker

Conversation

@cupicmarko

@cupicmarko cupicmarko commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Each page (index.html/admin.html) spawns its own dedicated storage worker, which installs an OPFS SQLite VFS (sahpool). Navigating between them raced the outgoing worker's OPFS handle release against the incoming worker's acquire, and the failure was consistently misreported:

  • OpfsSAHError's Display/Debug never interpolate the wrapped JsValue, so the lock-detection heuristic (is_opfs_locked_error) was matching against a string that could never contain the real DOMException text, always falling through to a generic "Failed to initialize" toast.
  • After fixing detection to inspect the DomException directly, a retry loop was added to tolerate the async release race — but pause_vfs() refuses to release handles while SQLite still has files open, and the worker never closed its connection, so the "release on pagehide" path was a silent no-op.

Fixes, in order of effect:

  • is_opfs_locked_error now matches on OpfsSAHError::CreateSyncAccessHandle and checks the wrapped DomException's name directly.
  • storage worker retries sahpool::install for ~2s on a detected lock before surfacing the "another tab" message, tolerating the normal async handle-release delay.
  • New Pause request: on the page's pagehide event, the main thread fire-and-forgets a Pause call; the worker now drops its live SQLite connection first (closing the VFS file) so pause_vfs() can actually succeed, releasing the OPFS pool before the browser tears the worker down.

Note: The issue is reproduced in Firefox

Each page (index.html/admin.html) spawns its own dedicated storage worker,
which installs an OPFS SQLite VFS (sahpool). Navigating between them raced
the outgoing worker's OPFS handle release against the incoming worker's
acquire, and the failure was consistently misreported:

- OpfsSAHError's Display/Debug never interpolate the wrapped JsValue, so
  the lock-detection heuristic (is_opfs_locked_error) was matching against
  a string that could never contain the real DOMException text, always
  falling through to a generic "Failed to initialize" toast.
- After fixing detection to inspect the DomException directly, a retry
  loop was added to tolerate the async release race — but pause_vfs()
  refuses to release handles while SQLite still has files open, and the
  worker never closed its connection, so the "release on pagehide" path
  was a silent no-op.

Fixes, in order of effect:
- is_opfs_locked_error now matches on OpfsSAHError::CreateSyncAccessHandle
  and checks the wrapped DomException's name directly.
- storage worker retries sahpool::install for ~2s on a detected lock
  before surfacing the "another tab" message, tolerating the normal
  async handle-release delay.
- New Pause request: on the page's `pagehide` event, the main thread
  fire-and-forgets a Pause call; the worker now drops its live SQLite
  connection first (closing the VFS file) so pause_vfs() can actually
  succeed, releasing the OPFS pool before the browser tears the worker
  down.
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