Skip to content

openBrowserWASQLiteOPFSDatabase() never settles while a frozen tab holds the database #1883

Description

@jwaltz
  • I've validated the bug against the latest version of DB packages

Describe the bug

If another tab has the database open and that tab is frozen, openBrowserWASQLiteOPFSDatabase() in a new tab never settles. The bundled OPFSCoopSyncVFS asks the current holder to hand over its access handles over a BroadcastChannel, then waits for the holder's Web Lock. A frozen tab can't answer. The open has no timeout or AbortSignal, so the caller can't give up and fall back to non-persisted sync. Anything waiting on the open, such as persisted collections reading their startup metadata, waits until the other tab thaws.

To Reproduce

A Vite app with @tanstack/browser-db-sqlite-persistence@0.2.23 and vite@8.3.1:

hang.html
<!doctype html>
<meta charset="utf-8" />
<title>Frozen holder repro</title>
<pre id="log">Opening…</pre>
<script type="module" src="./hang.js"></script>
hang.js
import { openBrowserWASQLiteOPFSDatabase } from "@tanstack/browser-db-sqlite-persistence";

// Tab A: load /hang.html and let it open the store. Freeze tab A, then load
// /hang.html in tab B. Tab B's open stays pending until tab A is thawed.
const log = document.querySelector("#log");
const started = performance.now();
const elapsed = () => `${((performance.now() - started) / 1000).toFixed(1)} s`;
const timer = setInterval(() => (log.textContent = `open pending for ${elapsed()}`), 250);
try {
  const db = await openBrowserWASQLiteOPFSDatabase({ databaseName: "repro.sqlite" });
  await db.execute("CREATE TABLE IF NOT EXISTS t (x)");
  await db.execute("INSERT INTO t VALUES (1)");
  log.textContent = `opened after ${elapsed()}`;
} catch (e) {
  log.textContent = `failed after ${elapsed()}: ${e.name}: ${e.message}`;
}
clearInterval(timer);
  1. Open /hang.html in tab A. It shows opened after 0.1 s.
  2. Freeze tab A by sending the DevTools protocol command Page.setWebLifecycleState with {"state": "frozen"} to it.
  3. Open /hang.html in tab B. It shows open pending for 15.0 s and keeps counting.
  4. Send {"state": "active"} to tab A. Tab B shows opened after 15.1 s.

main at 4c5a8de, which includes #1844, behaves the same when I build its opfs-database.ts against the 0.2.23 worker. Freezing fires freeze, not pagehide, so the new cleanup never runs.

Expected behavior

A way to bound the wait, such as an AbortSignal or timeout option on openBrowserWASQLiteOPFSDatabase(), so the caller can fall back to non-persisted sync. An abandoned open that completes later should release the database rather than keep holding it.

Desktop:

  • OS: Linux x86_64
  • Browser: Chrome, headless, driven over CDP
  • Version: 152.0.0.0

Additional context

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions