Skip to content

Commit 5f5cd5c

Browse files
authored
Throw error from validation failure (#1220)
Changes the connection pool behavior on errors during validation, these would be unintended behavior and as such the driver should throw an error if it occurs, rather than simply logging as was the case in the 5.24.1 patch release fix. Also updates the test to control for this behavior.
1 parent 9974f1a commit 5f5cd5c

File tree

3 files changed

+67
-13
lines changed

3 files changed

+67
-13
lines changed

packages/core/src/internal/pool/pool.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ class Pool<R extends unknown = unknown> {
262262
try {
263263
valid = await this._validateOnAcquire(acquisitionContext, resource)
264264
} catch (e) {
265-
if (this._log.isErrorEnabled()) {
266-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
267-
this._log.error(`Failure on validate ${resource}. This is a bug, please report it. Caused by: ${e.message}`)
268-
}
265+
resourceReleased(key, this._activeResourceCounts)
266+
pool.removeInUse(resource)
267+
await this._destroy(resource)
268+
throw e
269269
}
270270

271271
if (valid) {

packages/core/test/internal/pool/pool.test.ts

+59-5
Original file line numberDiff line numberDiff line change
@@ -969,10 +969,7 @@ describe('#unit Pool', () => {
969969
await conn2.release(address, conn2)
970970
})
971971

972-
it.each([
973-
['is not valid', (promise: any) => promise.resolve(false)],
974-
['validation fails', (promise: any) => promise.reject(new Error('failed'))]
975-
])('should create new connection if the current one when %s', async (_, resolver) => {
972+
it('should create new connection if the current one breaks due to being invalid', async () => {
976973
const conns: any[] = []
977974
const pool = new Pool<any>({
978975
// Hook into connection creation to track when and what connections that are
@@ -1020,7 +1017,7 @@ describe('#unit Pool', () => {
10201017
expect(conns.length).toEqual(1)
10211018

10221019
// should resolve the promise with the configured value
1023-
resolver(conns[0].promises[0])
1020+
conns[0].promises[0].resolve(false)
10241021

10251022
// getting the connection 1
10261023
const conn1 = await req0
@@ -1038,6 +1035,63 @@ describe('#unit Pool', () => {
10381035
expect(conns.length).toEqual(2)
10391036
})
10401037

1038+
it('should create new connection if the current one breaks from error during validation', async () => {
1039+
const conns: any[] = []
1040+
const pool = new Pool<any>({
1041+
// Hook into connection creation to track when and what connections that are
1042+
// created.
1043+
create: async (_, server, release) => {
1044+
// Create a fake connection that makes it possible control when it's connected
1045+
// and released from the outer scope.
1046+
const conn: any = {
1047+
server,
1048+
release
1049+
}
1050+
conns.push(conn)
1051+
return conn
1052+
},
1053+
validateOnAcquire: async (context, resource: any) => {
1054+
const promise = new Promise<boolean>((resolve, reject) => {
1055+
if (resource.promises == null) {
1056+
resource.promises = []
1057+
}
1058+
resource.promises.push({
1059+
resolve,
1060+
reject
1061+
})
1062+
})
1063+
1064+
return await promise
1065+
},
1066+
// Setup pool to only allow one connection
1067+
config: new PoolConfig(1, 100000)
1068+
})
1069+
// Make the first request for a connection, this will return a connection instantaneously
1070+
const conn0 = await pool.acquire({}, address)
1071+
expect(conns.length).toEqual(1)
1072+
1073+
// Releasing connection back to the pool, so it can be re-acquired.
1074+
await conn0.release(address, conn0)
1075+
1076+
// Request the same connection again, it will wait until resolve get called.
1077+
const req0 = pool.acquire({}, address)
1078+
expect(conns.length).toEqual(1)
1079+
1080+
// should resolve the promise with the configured value
1081+
conns[0].promises[0].reject(new Error('Failed'))
1082+
await expect(async () => await req0).rejects.toThrow()
1083+
1084+
// Request other connection, this should also resolve the same connection.
1085+
const conn2 = await pool.acquire({}, address)
1086+
expect(conns.length).toEqual(2)
1087+
1088+
await conn2.release(address, conn2)
1089+
expect(conns.length).toEqual(2)
1090+
expect(conn0).not.toBe(conn2)
1091+
expect(idleResources(pool, address)).toBe(1)
1092+
expect(resourceInUse(pool, address)).toBe(0)
1093+
})
1094+
10411095
it('should not time out if max pool size is not set', async () => {
10421096
let counter = 0
10431097

packages/neo4j-driver-deno/lib/core/internal/pool/pool.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ class Pool<R extends unknown = unknown> {
262262
try {
263263
valid = await this._validateOnAcquire(acquisitionContext, resource)
264264
} catch (e) {
265-
if (this._log.isErrorEnabled()) {
266-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
267-
this._log.error(`Failure on validate ${resource}. This is a bug, please report it. Caused by: ${e.message}`)
268-
}
265+
resourceReleased(key, this._activeResourceCounts)
266+
pool.removeInUse(resource)
267+
await this._destroy(resource)
268+
throw e
269269
}
270270

271271
if (valid) {

0 commit comments

Comments
 (0)