fix(platform): close startup subscription handoff gaps

This commit is contained in:
2026-09-05 10:02:45 +08:00
parent 3963b3b791
commit d177c52c3f
2 changed files with 301 additions and 13 deletions
@@ -138,20 +138,20 @@ export class PlatformRuntime {
const generation = this.startupGeneration + 1;
this.startupGeneration = generation;
this.lifecycle = 'starting';
this.options.scene.showLoading();
this.requireActiveStartup(generation);
const resourcesReady = this.beginReadyTask(
'resources',
this.options.loadResources,
generation,
);
const minimumDisplayReady = this.beginReadyTask(
'minimum-display',
this.options.waitForMinimumDisplay,
generation,
);
try {
this.options.scene.showLoading();
this.requireActiveStartup(generation);
const resourcesReady = this.beginReadyTask(
'resources',
this.options.loadResources,
generation,
);
const minimumDisplayReady = this.beginReadyTask(
'minimum-display',
this.options.waitForMinimumDisplay,
generation,
);
this.requireActiveStartup(generation);
const config = await this.options.resolveRuntimeConfig();
this.requireActiveStartup(generation);
@@ -204,7 +204,7 @@ export class PlatformRuntime {
this.router = router;
this.wire = wire;
this.requireActiveStartup(generation);
this.unsubscribeWire = wire.subscribe((event) => { this.onWireEvent(event); });
this.subscribeToWire(wire, generation);
this.requireActiveStartup(generation);
this.markReady('config');
this.lifecycle = 'running';
@@ -443,6 +443,49 @@ export class PlatformRuntime {
wire.stop();
}
private subscribeToWire(wire: PlatformWireClient, generation: number): void {
let actualUnsubscribe: (() => void) | null = null;
let releaseRequested = false;
let released = false;
const temporaryOwner = (): void => {
if (released) return;
if (actualUnsubscribe === null) {
releaseRequested = true;
return;
}
released = true;
const unsubscribe = actualUnsubscribe;
actualUnsubscribe = null;
unsubscribe();
};
this.unsubscribeWire = temporaryOwner;
const returnedUnsubscribe: unknown = wire.subscribe(
(event) => { this.onWireEvent(event); },
);
if (typeof returnedUnsubscribe !== 'function') {
throw new TypeError(
'WireClient.subscribe must return an unsubscribe function',
);
}
actualUnsubscribe = returnedUnsubscribe as () => void;
if (!releaseRequested) return;
const cleanupErrors: unknown[] = [];
this.captureCleanupError(cleanupErrors, temporaryOwner);
if (cleanupErrors.length === 0) this.requireActiveStartup(generation);
const primary = this.fatalError
?? new Error(`PlatformRuntime startup interrupted while ${this.lifecycle}`);
const failure = this.failureError(
'subscription handoff',
primary,
cleanupErrors,
);
if (this.fatalError !== null) this.fatalError = failure;
throw failure;
}
private captureCleanupError(errors: unknown[], operation: () => void): void {
try {
operation();