Skip to content

ADR-0033: Exclusive ownership of each browser scope

Context

The PHP BroadcastChannel and persistence journal are scoped, not tab-specific. Duplicated tabs or explicit ?scope= URLs can start two PHP workers against the same channel and journal. Both workers can execute one POST; the Service Worker only returns the first reply. Adding a runtime suffix does not protect two tabs using the same runtime or their shared journal.

Decision

Acquire an exclusive native Web Lock (omeka-playground-owner:<scope>) in the remote host before storage, cache reset, or worker initialization. Use ifAvailable to reject a second owner with a message; it must be explicitly reloaded after the owner closes. Fail closed without Web Locks.

Terminate the worker on pagehide before releasing ownership. Reload a restored BFCache document. Give each iframe generation its own shell channel, and enable HTTP listening only after authoritative worker configuration. Retain the scoped HTTP channel, UUID response correlation, and GET/HEAD-only crash replay policy.

Consequences

Independent scopes remain concurrent. Reload, Reset, runtime changes and crash recovery retain existing journal names and paths. Ownership changes do not queue or replay POST requests and do not delete persisted data. Existing tabs running older code do not participate; close them and refresh stale Service Worker caches when deploying this change. Web Locks are now required; Safari is not validated by the Chromium/Firefox regression tests.