From 9325cb2697f07da48fb7a91ace52943bb6203ff2 Mon Sep 17 00:00:00 2001 From: Xetera Date: Mon, 27 Apr 2026 17:37:27 +0300 Subject: [PATCH] fix: analyzer crashing when trying to remove the database with force --- src/remote/query-optimizer.ts | 39 +++++++++++++++++++++-------------- src/remote/remote.ts | 3 ++- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/remote/query-optimizer.ts b/src/remote/query-optimizer.ts index f27e312b..edf50abf 100644 --- a/src/remote/query-optimizer.ts +++ b/src/remote/query-optimizer.ts @@ -52,6 +52,7 @@ export class QueryOptimizer extends EventEmitter { private target?: Target; private semaphore = new Sema(QueryOptimizer.MAX_CONCURRENCY); private _finish = Promise.withResolvers(); + private _inflight: Promise = Promise.resolve(); private _validQueriesProcessed = 0; private _invalidQueries = 0; @@ -158,6 +159,11 @@ export class QueryOptimizer extends EventEmitter { this._validQueriesProcessed = 0; } + async drain(): Promise { + this.stop(); + await this._inflight; + } + async restart({ clearQueries } = { clearQueries: false }) { this.semaphore = new Sema(QueryOptimizer.MAX_CONCURRENCY); if (clearQueries) { @@ -297,21 +303,24 @@ export class QueryOptimizer extends EventEmitter { break; } this._validQueriesProcessed++; - const optimization = await this.optimizeQuery( - optimized, - this.target, - { timeoutMs: this.calculateTimeoutRetryDelay(optimized) }, - ); - this.queriedSinceVacuum++; - if (this.queriedSinceVacuum > QueryOptimizer.vacuumThreshold) { - await this.vacuum(); - this.queriedSinceVacuum = 0; - } - - this.queries.set( - optimized.hash, - optimized.withOptimization(optimization), - ); + // mark the latest inflight request so it can be awaited in drain() + this._inflight = (async () => { + const optimization = await this.optimizeQuery( + optimized, + this.target!, + { timeoutMs: this.calculateTimeoutRetryDelay(optimized) }, + ); + this.queriedSinceVacuum++; + if (this.queriedSinceVacuum > QueryOptimizer.vacuumThreshold) { + await this.vacuum(); + this.queriedSinceVacuum = 0; + } + this.queries.set( + optimized.hash, + optimized.withOptimization(optimization), + ); + })(); + await this._inflight; } } finally { this.running = false; diff --git a/src/remote/remote.ts b/src/remote/remote.ts index 7311839b..e9905de8 100644 --- a/src/remote/remote.ts +++ b/src/remote/remote.ts @@ -255,9 +255,10 @@ export class Remote extends EventEmitter { this.generation = nextGeneration; this.optimizingDbUDRL = this.optimizingDbUDRL.withDatabaseName(nextDbName); this.optimizer.updateConnectable(this.optimizingDbUDRL); + await this.optimizer.drain(); // these cannot be run in the same `exec` block as that implicitly creates transactions await baseDb.exec( - `drop database if exists ${prevDbName} with (force);`, + `drop database if exists ${prevDbName};`, ); }