Disable the shared worker on Android (same as is done for iOS already) (#8457)

* Revert "Reload when PWA shared worker is killed by Android (#8322)"

This reverts commit 62ced9aa2b.

* Disable shared worker in PWA on Android
This commit is contained in:
Martin Lukas
2026-07-13 20:49:23 +00:00
committed by GitHub
parent 0146471d0e
commit 1a4f810ecd
8 changed files with 30 additions and 42 deletions
@@ -38,7 +38,8 @@ const worker = startBrowserBackend({
},
createSharedWorker: () =>
new SharedBrowserServerWorker({ name: 'actual-backend' }),
forceDirectWorker: Platform.isPlaywright || Platform.isIOS,
forceDirectWorker:
Platform.isPlaywright || Platform.isIOS || Platform.isAndroid,
});
let isUpdateReadyForDownload = false;
@@ -74,6 +74,8 @@ export function startBrowserBackend(
'SharedArrayBufferOverride',
),
});
bridge.markInitialized();
window.addEventListener('beforeunload', () => {
sharedPort.postMessage({ type: 'tab-closing' });
});
@@ -2,11 +2,6 @@ import { initBackend as initSQLBackend } from 'absurd-sql/dist/indexeddb-main-th
import { logger } from '#platform/server/log';
// After sending a __resume-tab ping we wait for any response from the shared worker.
// A live shared worker replies well below this threshold; no response means
// it might have been killed by the OS, and we need to reload.
const RESUME_TAB_RESPONSE_TIMEOUT_MS = 1_000;
type BridgeMessage = { type?: string; [key: string]: unknown };
/** The Worker-like surface the connection layer interacts with. */
@@ -33,8 +28,9 @@ export class WorkerBridge {
_onmessage: ((e: MessageEvent) => void) | null;
_listeners: Array<{ type: string; handler: (e: MessageEvent) => void }>;
_started: boolean;
_isInitialized: boolean;
_currentBudgetId: string | null;
_sharedWorkerLivenessTimeout: { start: () => void; clear: () => void };
_wasHidden: boolean;
_onVisibilityChange: () => void;
localBackendWorker: Worker | null;
backendWorkerUrl: URL;
@@ -44,21 +40,19 @@ export class WorkerBridge {
this._onmessage = null;
this._listeners = [];
this._started = false;
this._isInitialized = false;
this._currentBudgetId = null;
this._sharedWorkerLivenessTimeout =
this._createSharedWorkerLivenessTimeout();
this._wasHidden = document.visibilityState === 'hidden';
this.localBackendWorker = null;
this.backendWorkerUrl = backendWorkerUrl;
this._onVisibilityChange = () => {
if (document.visibilityState === 'hidden' || !this._started) {
return;
if (document.visibilityState === 'hidden') {
this._wasHidden = true;
} else if (this._wasHidden) {
this._wasHidden = false;
this._resumeAssociation();
}
// Cancel any pending reload from a prior transition, then re-check shared worker's liveness
this._sharedWorkerLivenessTimeout.clear();
this._resumeAssociation();
this._sharedWorkerLivenessTimeout.start();
};
// Listen for all messages from the SharedWorker port
@@ -112,9 +106,6 @@ export class WorkerBridge {
}
_onSharedMessage(event: MessageEvent) {
// Cancel any pending reload — the shared worker is alive.
this._sharedWorkerLivenessTimeout.clear();
const msg = event.data as BridgeMessage;
// Elected as leader: create the real backend Worker on this tab
@@ -192,6 +183,10 @@ export class WorkerBridge {
this._dispatch(event);
}
markInitialized() {
this._isInitialized = true;
}
_normalizeBudgetId(budgetId: string | null): string | null {
if (
typeof budgetId === 'string' &&
@@ -212,6 +207,9 @@ export class WorkerBridge {
}
_resumeAssociation() {
if (!this._isInitialized) {
return;
}
this._sharedPort.postMessage({
type: '__resume-tab',
budgetId: this._currentBudgetId,
@@ -273,21 +271,4 @@ export class WorkerBridge {
localWorker.postMessage(initMsg);
}
_createSharedWorkerLivenessTimeout() {
let timer: ReturnType<typeof setTimeout> | null = null;
return {
start() {
timer = setTimeout(() => {
window.location.reload();
}, RESUME_TAB_RESPONSE_TIMEOUT_MS);
},
clear() {
if (timer !== null) {
clearTimeout(timer);
timer = null;
}
},
};
}
}
@@ -5,3 +5,4 @@ export const env: 'web' | 'mobile' | 'unknown' = 'unknown';
export const isBrowser: boolean = false;
export const isIOSAgent = false;
export const isAndroid = false;
@@ -20,3 +20,4 @@ export const isBrowser: typeof T.isBrowser = false;
export const isIOSAgent: typeof T.isIOSAgent = false;
export const isIOS: typeof T.isIOS = false;
export const isAndroid: typeof T.isAndroid = false;
@@ -25,6 +25,8 @@ const userAgent = navigator.userAgent;
// True for all browsers on iOS (iPhone/iPad/iPod) — not macOS.
export const isIOS = /iP(hone|ad|od)/.test(userAgent);
export const isAndroid = /Android/.test(userAgent);
// True only for Safari on iOS — Chrome (CriOS), Firefox (FxiOS), Edge (EdgiOS),
// etc. carry their own tokens and are excluded.
export const isIOSAgent =
@@ -0,0 +1,6 @@
---
category: Bugfixes
authors: [martin-lukas]
---
Fix app becoming unresponsive on Android when reopening after being in the background for a while.
@@ -1,6 +0,0 @@
---
category: Bugfixes
authors: [martin-lukas]
---
Fixed issue on Android where app becomes unresponsive when reopening after period of inactivity.