From 3f335175f96dc3b608c558109d7f3aa95906ef97 Mon Sep 17 00:00:00 2001 From: Darick Tong <132324914+darkgnotic@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:30:54 -0800 Subject: [PATCH] fix(zero-cache): avoid perpetuating work when clients have disconnected (#3408) --- .../src/services/view-syncer/view-syncer.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/zero-cache/src/services/view-syncer/view-syncer.ts b/packages/zero-cache/src/services/view-syncer/view-syncer.ts index f0582d123..683ccf6c6 100644 --- a/packages/zero-cache/src/services/view-syncer/view-syncer.ts +++ b/packages/zero-cache/src/services/view-syncer/view-syncer.ts @@ -162,7 +162,7 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { return; // view-syncer has been shutdown } // If all clients have disconnected, cancel all pending work. - if (this.#checkForShutdownConditionsInLock()) { + if (await this.#checkForShutdownConditionsInLock()) { this.#lc.info?.('shutting down'); this.#stateChanges.cancel(); // Note: #stateChanges.active becomes false. return; @@ -278,11 +278,6 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { this.#shutdownTimer ??= setTimeout(async () => { this.#shutdownTimer = null; - // Keep the view-syncer alive if there are pending rows being flushed. - // It's better to do this before shutting down since it may take a - // while, during which new connections may come in. - await this.#cvrStore.flushed(this.#lc).catch(e => this.#lc.error?.(e)); - // All lock tasks check for shutdown so that queued work is immediately // canceled when clients disconnect. Queue an empty task to ensure that // this check happens. @@ -290,19 +285,23 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { }, delayMs); } - #checkForShutdownConditionsInLock(): boolean { + async #checkForShutdownConditionsInLock(): Promise { if (this.#clients.size > 0) { return false; // common case. } + + // Keep the view-syncer alive if there are pending rows being flushed. + // It's better to do this before shutting down since it may take a + // while, during which new connections may come in. + await this.#cvrStore.flushed(this.#lc); + if (Date.now() <= this.#keepAliveUntil) { this.#scheduleShutdown(this.#keepaliveMs); // check again later return false; } - if (this.#cvrStore.hasPendingUpdates()) { - this.#scheduleShutdown(0); // check again after #cvrStore.flushed() - return false; - } - return true; + + // If no clients have connected while waiting for the row flush, shutdown. + return this.#clients.size === 0; } #deleteClient(clientID: string, client: ClientHandler) {