@cap-js/db-service 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@
4
4
  - The format is based on [Keep a Changelog](http://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [2.1.1](https://github.com/cap-js/cds-dbs/compare/db-service-v2.1.0...db-service-v2.1.1) (2025-06-06)
8
+
9
+
10
+ ### Fixed
11
+
12
+ * Better opt in flag for builtin generic pool ([#1234](https://github.com/cap-js/cds-dbs/issues/1234)) ([98282ff](https://github.com/cap-js/cds-dbs/commit/98282ffd86cb143ebe9000f75b4a51156f6c3539))
13
+ * miscellaneous fixes for builtin pool ([#1235](https://github.com/cap-js/cds-dbs/issues/1235)) ([c657a0b](https://github.com/cap-js/cds-dbs/commit/c657a0ba2292fd429adb1b69aa9ead3eec9d5be0))
14
+
7
15
  ## [2.1.0](https://github.com/cap-js/cds-dbs/compare/db-service-v2.0.1...db-service-v2.1.0) (2025-06-04)
8
16
 
9
17
 
@@ -1,10 +1,8 @@
1
1
  const cds = require('@sap/cds')
2
2
  const LOG = cds.log('db')
3
3
 
4
- const createPool = (factory, config) => {
5
- if (cds.requires.db?.pool?.builtin) return new Pool(factory, config)
6
- return require('generic-pool').createPool(factory, config)
7
- }
4
+ const use_new_pool = cds.requires.db?.pool?.builtin || cds.env.features.pool === 'builtin'
5
+ const createPool = use_new_pool ? (...args) => new Pool(...args) : require('generic-pool').createPool
8
6
 
9
7
  function ConnectionPool (factory, tenant) {
10
8
  let bound_factory = { __proto__: factory, create: factory.create.bind(null, tenant) }
@@ -35,7 +33,7 @@ function TrackedConnectionPool (factory, tenant) {
35
33
  }
36
34
 
37
35
  const DEBUG = /\bpool\b/.test(process.env.DEBUG)
38
- module.exports = DEBUG && !cds.requires.db?.pool?.builtin ? TrackedConnectionPool : ConnectionPool
36
+ module.exports = DEBUG && !use_new_pool ? TrackedConnectionPool : ConnectionPool
39
37
 
40
38
  // Drop-in replacement for https://github.com/coopernurse/node-pool
41
39
  // TODO: fifo: true? relevant for our use case?
@@ -57,7 +55,7 @@ const RequestState = Object.freeze({
57
55
 
58
56
  class Request {
59
57
  constructor (ttl) {
60
- this.state = 'pending'
58
+ this.state = RequestState.PENDING
61
59
  this.promise = new Promise((resolve, reject) => {
62
60
  this._resolve = value => {
63
61
  clearTimeout(this._timeout)
@@ -71,12 +69,12 @@ class Request {
71
69
  }
72
70
  if (typeof ttl === 'number' && ttl >= 0) {
73
71
  const err = new Error(`Pool resource could not be acquired within ${ttl / 1000}s`)
74
- this._timeout = setTimeout(() => this._reject(err), ttl)
72
+ this._timeout = setTimeout(() => this._reject(err), ttl).unref()
75
73
  }
76
74
  })
77
75
  }
78
- resolve (v) { if (this.state === 'pending') this._resolve(v) }
79
- 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) }
80
78
  }
81
79
 
82
80
  class PooledResource {
@@ -133,7 +131,9 @@ constructor (factory, options = {}) {
133
131
  this._queue = []
134
132
 
135
133
  this.#scheduleEviction()
136
- 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()
137
137
  }
138
138
 
139
139
  async acquire() {
@@ -173,7 +173,7 @@ constructor (factory, options = {}) {
173
173
 
174
174
  async clear() {
175
175
  await Promise.allSettled(Array.from(this._creates))
176
- 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)))
177
177
  }
178
178
 
179
179
  async #createResource() {
@@ -250,16 +250,23 @@ constructor (factory, options = {}) {
250
250
  this._available.delete(resource)
251
251
  this._loans.delete(resource.obj)
252
252
  try {
253
- 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
+ }
254
263
  } catch (e) {
255
264
  LOG.error(e)
256
265
  /* FIXME: We have to ignore errors here due to a TypeError in hdb */
257
266
  /* This was also a problem with the old (generic-pool) implementation */
258
267
  /* Root cause in hdb needs to be fixed */
259
268
  } finally {
260
- if (!this._draining && this.size < this.options.min) {
261
- await this.#createResource()
262
- }
269
+ if (!this._draining && this.size < this.options.min) this.#createResource()
263
270
  }
264
271
  }
265
272
 
@@ -268,14 +275,19 @@ constructor (factory, options = {}) {
268
275
  if (evictionRunIntervalMillis <= 0) return
269
276
  this._scheduledEviction = setTimeout(async () => {
270
277
  try {
271
- const resourcesToEvict = Array.from(this._available)
272
- .slice(0, numTestsPerEvictionRun)
273
- .filter(resource => {
274
- const idleTime = Date.now() - resource.lastIdleTime
275
- const softEvict = softIdleTimeoutMillis > 0 && softIdleTimeoutMillis < idleTime && min < this._available.size
276
- return softEvict || idleTimeoutMillis < idleTime
277
- })
278
- 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)
279
291
  } finally {
280
292
  this.#scheduleEviction()
281
293
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/db-service",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "CDS base database service",
5
5
  "homepage": "https://github.com/cap-js/cds-dbs/tree/main/db-service#cds-base-database-service",
6
6
  "repository": {