Skip to content

Commit c657a0b

Browse files
fix: miscellaneous fixes for builtin pool (#1235)
- Add missing `.unref()` to resource request timer - Implements `destroyTimeoutMillis` - `min > 0` (non-default) is handled correctly --------- Co-authored-by: Johannes Vogel <[email protected]>
1 parent 98282ff commit c657a0b

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

db-service/lib/common/generic-pool.js

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const RequestState = Object.freeze({
5555

5656
class Request {
5757
constructor (ttl) {
58-
this.state = 'pending'
58+
this.state = RequestState.PENDING
5959
this.promise = new Promise((resolve, reject) => {
6060
this._resolve = value => {
6161
clearTimeout(this._timeout)
@@ -69,12 +69,12 @@ class Request {
6969
}
7070
if (typeof ttl === 'number' && ttl >= 0) {
7171
const err = new Error(`Pool resource could not be acquired within ${ttl / 1000}s`)
72-
this._timeout = setTimeout(() => this._reject(err), ttl)
72+
this._timeout = setTimeout(() => this._reject(err), ttl).unref()
7373
}
7474
})
7575
}
76-
resolve (v) { if (this.state === 'pending') this._resolve(v) }
77-
reject (e) { if (this.state === 'pending') this._reject(e) }
76+
resolve (v) { if (this.state === RequestState.PENDING) this._resolve(v) }
77+
reject (e) { if (this.state === RequestState.PENDING) this._reject(e) }
7878
}
7979

8080
class PooledResource {
@@ -131,7 +131,9 @@ constructor (factory, options = {}) {
131131
this._queue = []
132132

133133
this.#scheduleEviction()
134-
for (let i = 0; i < this.options.min - this.size; i++) this.#createResource()
134+
135+
const initial = this.options.min - this.size
136+
for (let i = 0; i < initial; i++) this.#createResource()
135137
}
136138

137139
async acquire() {
@@ -171,7 +173,7 @@ constructor (factory, options = {}) {
171173

172174
async clear() {
173175
await Promise.allSettled(Array.from(this._creates))
174-
await Promise.allSettled(Array.from(this._available).map(resource => this.#destroy(resource)))
176+
await Promise.allSettled(Array.from(this._all).map(resource => this.#destroy(resource)))
175177
}
176178

177179
async #createResource() {
@@ -248,16 +250,23 @@ constructor (factory, options = {}) {
248250
this._available.delete(resource)
249251
this._loans.delete(resource.obj)
250252
try {
251-
await this.factory.destroy(resource.obj)
253+
const destroyPromise = Promise.resolve(this.factory.destroy(resource.obj))
254+
const { destroyTimeoutMillis } = this.options
255+
if (destroyTimeoutMillis && destroyTimeoutMillis > 0) {
256+
const timeout = new Promise((_, reject) =>
257+
setTimeout(() => reject(new Error(`Resource destruction timed out after ${destroyTimeoutMillis}ms`)), destroyTimeoutMillis).unref()
258+
)
259+
await Promise.race([destroyPromise, timeout])
260+
} else {
261+
await destroyPromise
262+
}
252263
} catch (e) {
253264
LOG.error(e)
254265
/* FIXME: We have to ignore errors here due to a TypeError in hdb */
255266
/* This was also a problem with the old (generic-pool) implementation */
256267
/* Root cause in hdb needs to be fixed */
257268
} finally {
258-
if (!this._draining && this.size < this.options.min) {
259-
await this.#createResource()
260-
}
269+
if (!this._draining && this.size < this.options.min) this.#createResource()
261270
}
262271
}
263272

@@ -266,14 +275,19 @@ constructor (factory, options = {}) {
266275
if (evictionRunIntervalMillis <= 0) return
267276
this._scheduledEviction = setTimeout(async () => {
268277
try {
269-
const resourcesToEvict = Array.from(this._available)
270-
.slice(0, numTestsPerEvictionRun)
271-
.filter(resource => {
272-
const idleTime = Date.now() - resource.lastIdleTime
273-
const softEvict = softIdleTimeoutMillis > 0 && softIdleTimeoutMillis < idleTime && min < this._available.size
274-
return softEvict || idleTimeoutMillis < idleTime
275-
})
276-
await Promise.all(resourcesToEvict.map(resource => this.#destroy(resource)))
278+
const evictionCandidates = Array.from(this._available).slice(0, numTestsPerEvictionRun)
279+
const destructionPromises = []
280+
for (const resource of evictionCandidates) {
281+
const idleTime = Date.now() - resource.lastIdleTime
282+
const softEvict = softIdleTimeoutMillis > 0 && softIdleTimeoutMillis < idleTime && this._all.size > min
283+
const hardEvict = idleTimeoutMillis < idleTime
284+
if (softEvict || hardEvict) {
285+
if (this._available.delete(resource)) {
286+
destructionPromises.push(this.#destroy(resource))
287+
}
288+
}
289+
}
290+
await Promise.all(destructionPromises)
277291
} finally {
278292
this.#scheduleEviction()
279293
}

0 commit comments

Comments
 (0)