fix: [SDK-4754] guard IndexedDB reads + writes from iOS Safari PWA wedge#1472
Conversation
The 160605 fix only guarded the Options store, but the iOS Safari PWA WebKit readwrite wedge is DB-wide: once init clears the Options write, it re-hangs at the next unguarded write (operation queue / model-store persistence). Generalize the timeout + page-scoped circuit breaker to every readwrite op (put/delete/clear) across all stores.
fadi-george
left a comment
There was a problem hiding this comment.
Changes seem fine, double check nothing breaks from this "wedge" logic
The 1.5s timeout makes the readwrite promise resolve, but the underlying WebKit IndexedDB transaction stays open and serializes every later op on that object store behind it -- including reads. Guarding only writes let init() crawl past the wedged Options write and then hang on the first post-wedge read of the same store (getSubscription's Options reads during storeInitialValues), reproducing the ~30 min stall. Route get/getAll through the same timeout + page-scoped circuit breaker as put/delete/clear: once wedged, reads short-circuit to a fallback (get -> undefined, getAll -> []) and a read that itself stalls also trips the breaker. Dropped reads fall back to the in-memory model state hydrated before the wedge.
Extend the breaker test to verify that once a wedged write trips the circuit breaker, reads short-circuit too (get -> undefined, getAll -> []), locking in the guard that keeps init() from hanging on the first post-wedge read of the wedged store.
After init, Page A now calls login + addTag so the operations store keeps getting writes on every load. This mirrors the customer's app behavior and reliably reproduces the readwrite wedge (and the subsequent same-store read hang) that the guard fix addresses.
|
A few things worth knowing when reviewing: 1. Why reads needed guarding too 2. It's possible that a benign |
Description
1 Line Summary
Extend the iOS Safari PWA IndexedDB wedge guard to cover reads as well as writes, so
OneSignal.init()no longer re-hangs ~30 min after a push subscription on subsequent navigations.Details
Background: the 160605 fix (#1468) capped writes to the
Optionsstore with a timeout + page-scoped circuit breaker. On-device verification showed the WebKitreadwritewedge is DB-wide, notOptions-specific, so this branch first generalized the guard to everyreadwriteop (put/delete/clear) across all stores.That still wasn't enough. The key insight, confirmed with on-device breadcrumb logging:
readwritetransaction stays open. WebKit then serializes every later op queued behind it on that object store — including reads.Optionswrite, advance pastinternalInit/sessionInit, then hang on the first post-wedge read of the same store —getSubscription'sOptionsreads insidestoreInitialValues. Reads on other stores (Ids/*) completed fine, which is why the hang looked like it moved.This change routes
get/getAllthrough the same timeout + circuit breaker as the writes:guardReadwrite→ a genericguard(label, op, fallback); renamesreadwriteWedged→dbWedged,READWRITE_TIMEOUT_MS→DB_TIMEOUT_MS.isReadwriteWedged()is kept as the exported getter (consumed byinitSaveState's app-ID-deferral bail-out).get→undefined,getAll→[]. A read that itself stalls also trips the breaker.The
preview/pageA.htmlrepro now callslogin+addTagafter init so theoperationsstore keeps getting writes on every load — this mirrors the customer's app and reliably triggers the wedge + same-store read hang. (Kept in this PR to make the fix verifiable; can be reverted before/after merge.)Systems Affected
Validation
Tests
Info
vp check: 0 errors.vp test --run: 519 passed. The breaker regression test now asserts that after a wedged write trips the breaker, reads short-circuit too (get→undefined,getAll→[]), not just writes.vp run build:prod: clean, size-limit within budget, API validation passed.Confirmed on device (iOS Safari PWA, clean slate per run): delete
ONE_SIGNAL_SDK_DB/ reinstall PWA → Page A → Page B → Register → B → A. The breaker trips once (db.put(...) timed outwarning), all subsequent ops short-circuit, andinit()completes in ~1.6s instead of hanging ~30 min.Checklist
Screenshots
Checklist
Related Tickets