Skip to content

Commit 03509ef

Browse files
authored
fix: reuse pool executor in strategy (#1232)
Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
1 parent 83c4dc7 commit 03509ef

2 files changed

Lines changed: 52 additions & 1 deletion

File tree

src/internal/database/pg-connection.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class TestablePgPoolStrategy extends PgPoolStrategy {
2424
setCurrentPoolForTest(pool: Pool): void {
2525
this.pool = pool
2626
}
27+
28+
getCachedExecutorPoolForTest(): Pool | undefined {
29+
return Reflect.get(this, 'executorPool') as Pool | undefined
30+
}
2731
}
2832

2933
function createPoolStrategySettings(
@@ -2141,3 +2145,39 @@ describe('PgTenantConnection payload serialization', () => {
21412145
}
21422146
})
21432147
})
2148+
2149+
describe('PgPoolStrategy executor reuse', () => {
2150+
it('reuses one executor per physical pool and rebuilds it when the pool is replaced', () => {
2151+
const strategy = new TestablePgPoolStrategy(createPoolStrategySettings())
2152+
const poolA = { options: { max: 8 } } as unknown as Pool
2153+
strategy.setCurrentPoolForTest(poolA)
2154+
2155+
const first = strategy.acquire()
2156+
expect(strategy.acquire()).toBe(first)
2157+
2158+
strategy.rebalance({ maxConnections: 4 })
2159+
expect(strategy.acquire()).toBe(first)
2160+
2161+
const poolB = { options: { max: 8 } } as unknown as Pool
2162+
strategy.setCurrentPoolForTest(poolB)
2163+
const replacement = strategy.acquire()
2164+
expect(replacement).not.toBe(first)
2165+
expect(strategy.acquire()).toBe(replacement)
2166+
})
2167+
2168+
it('releases the cached executor pool when the strategy is destroyed', async () => {
2169+
const strategy = new TestablePgPoolStrategy(createPoolStrategySettings())
2170+
const pool = {
2171+
options: { max: 8 },
2172+
end: vi.fn().mockResolvedValue(undefined),
2173+
} as unknown as Pool
2174+
strategy.setCurrentPoolForTest(pool)
2175+
2176+
strategy.acquire()
2177+
expect(strategy.getCachedExecutorPoolForTest()).toBe(pool)
2178+
2179+
await strategy.destroy()
2180+
2181+
expect(strategy.getCachedExecutorPoolForTest()).toBeUndefined()
2182+
})
2183+
})

src/internal/database/pg-connection.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,18 @@ export type PgCancelConnectionTarget =
134134
export class PgPoolStrategy {
135135
protected pool?: Pool
136136
protected tlsSession?: TlsSessionSlot
137+
private executor?: PgPoolExecutor
138+
private executorPool?: Pool
137139

138140
constructor(protected readonly options: PoolStrategySettings) {}
139141

140142
acquire(): PgPoolExecutor {
141-
return new PgPoolExecutor(this.getPool())
143+
const pool = this.getPool()
144+
if (!this.executor || this.executorPool !== pool) {
145+
this.executor = new PgPoolExecutor(pool)
146+
this.executorPool = pool
147+
}
148+
return this.executor
142149
}
143150

144151
async destroy(): Promise<void> {
@@ -148,6 +155,10 @@ export class PgPoolStrategy {
148155
return
149156
}
150157

158+
if (this.executorPool === originalPool) {
159+
this.executor = undefined
160+
this.executorPool = undefined
161+
}
151162
this.pool = undefined
152163
await this.drainPool(originalPool, 'destroy')
153164
}

0 commit comments

Comments
 (0)