diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-09 10:32:13 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-09 10:32:13 +0200 |
| commit | cb43495f998015850f34829329aa4509bd55d2cb (patch) | |
| tree | 667c26586010496056b71627f2d5b54cfe9540f5 /packages/meshbay-hub/src | |
| parent | fc148e185c01b2e25361c7625a67d310d2e1d288 (diff) | |
| download | meshbay-cb43495f998015850f34829329aa4509bd55d2cb.tar.gz | |
fix(spa): repair a bypassed page in seconds, not half a minute
The repair worked but arrived too late to help: about thirty seconds after a
hard reload, by which time four downloads had been started and hung, and the
page reloading under them read as an unexplained refresh.
Two delays, both removed.
`_claimController` waited its whole control budget before asking for the claim.
A page that is uncontrolled while an active worker exists will never be claimed
on its own -- a document fetched by a hard reload is exactly that shape -- so
the fifteen seconds were spent waiting for something that was not coming. The
claim is now asked for first; waiting is the fallback, not the opening move.
Measured in the harness: 6042ms of a 6000ms budget before, milliseconds after.
And a download that starts while the self-test is still running now waits for
it rather than racing it. Otherwise the click spends both its attempts failing
on a path that is about to be repaired, which is what put four frozen rows on
screen.
Hub suite 836 passed. Both new cases were checked against the unfixed source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
Diffstat (limited to 'packages/meshbay-hub/src')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/downloads.js | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/downloads.js b/packages/meshbay-hub/src/meshbay_hub/static/downloads.js index b1eade6..87d18b7 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/downloads.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/downloads.js @@ -338,6 +338,16 @@ async function _claimController(budgetMs) { // requests never reach the fetch handler, so the worker would take our stream // and never be asked for it — the download then freezes after exactly one // chunk, which is how that was found. + // + // Ask for the claim *before* waiting, not after. A page that is uncontrolled + // while an active worker exists will not be claimed on its own — a document + // fetched by a hard reload is exactly that shape — so the whole control + // budget is spent waiting for something that is not coming, and it was: about + // thirty seconds during which somebody clicks download and watches four rows + // hang. Asking first costs one message and makes the common case immediate. + if (!navigator.serviceWorker.controller && reg.active) { + try { reg.active.postMessage({ type: 'mbdl-claim' }); } catch { /* gone */ } + } const controller = await _awaitControl(left()); if (controller) return controller; // Active but not controlling after the whole budget. `sw.js` calls @@ -367,10 +377,17 @@ async function _claimController(budgetMs) { */ export function primeServiceWorker() { if (!STREAMS_VIA_SW) return; - serviceWorker().then((worker) => worker && _repairIfBypassed(worker)) + _priming = serviceWorker() + .then((worker) => worker && _repairIfBypassed(worker)) .catch(() => {}); } +// Resolved once the check below has run. A download that starts while it is +// still in flight waits for it rather than racing it: on a page that turns out +// to be unservable the click would otherwise spend thirty seconds failing on a +// path that is about to be repaired. +let _priming = null; + // How long to wait for the worker to answer the one-byte self-test below. // Milliseconds when it works; a page that cannot stream at all is worth four // seconds to find out about, once, at boot. @@ -495,6 +512,7 @@ export async function openStreamedDownload(filename, size = 0, { servedMs = SW_SERVED_BUDGET_MS, attempts = SW_ATTEMPTS, } = {}) { + if (_priming) { try { await _priming; } catch { /* reported already */ } } for (let attempt = 1; attempt <= attempts; attempt++) { const target = await _attemptStreamedDownload( filename, size, attempt, controlMs, servedMs); |