Skip to content

Commit 551f51c

Browse files
bigmontzrobsdedude
andauthored
Add support for error cause in Neo4jError and Routing errors (#960)
Root causes of routing issue were suppressed by the routing error message. This change enables the `Neo4jError` object use the `cause` property for giving more context about the error. This also improves the routing error by making use of the error `cause`. `Error.cause` is a new feature in JS, see which runtime already implemented it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error Co-authored-by: Robsdedude <dev@rouvenbauer.de>
1 parent a582fd6 commit 551f51c

File tree

4 files changed

+162
-108
lines changed

4 files changed

+162
-108
lines changed

packages/bolt-connection/src/connection-provider/connection-provider-routing.js

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
121121
this.forgetWriter(address, database || DEFAULT_DB_NAME)
122122
return newError(
123123
'No longer possible to write to server at ' + address,
124-
SESSION_EXPIRED
124+
SESSION_EXPIRED,
125+
error
125126
)
126127
}
127128

@@ -345,7 +346,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
345346
) {
346347
// we start with seed router, no routers were probed before
347348
const seenRouters = []
348-
let newRoutingTable = await this._fetchRoutingTableUsingSeedRouter(
349+
let [newRoutingTable, error] = await this._fetchRoutingTableUsingSeedRouter(
349350
seenRouters,
350351
this._seedRouter,
351352
currentRoutingTable,
@@ -357,18 +358,21 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
357358
this._useSeedRouter = false
358359
} else {
359360
// seed router did not return a valid routing table - try to use other known routers
360-
newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
361+
const [newRoutingTable2, error2] = await this._fetchRoutingTableUsingKnownRouters(
361362
knownRouters,
362363
currentRoutingTable,
363364
bookmarks,
364365
impersonatedUser
365366
)
367+
newRoutingTable = newRoutingTable2
368+
error = error2 || error
366369
}
367370

368371
return await this._applyRoutingTableIfPossible(
369372
currentRoutingTable,
370373
newRoutingTable,
371-
onDatabaseNameResolved
374+
onDatabaseNameResolved,
375+
error
372376
)
373377
}
374378

@@ -379,7 +383,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
379383
impersonatedUser,
380384
onDatabaseNameResolved
381385
) {
382-
let newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
386+
let [newRoutingTable, error] = await this._fetchRoutingTableUsingKnownRouters(
383387
knownRouters,
384388
currentRoutingTable,
385389
bookmarks,
@@ -388,7 +392,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
388392

389393
if (!newRoutingTable) {
390394
// none of the known routers returned a valid routing table - try to use seed router address for rediscovery
391-
newRoutingTable = await this._fetchRoutingTableUsingSeedRouter(
395+
[newRoutingTable, error] = await this._fetchRoutingTableUsingSeedRouter(
392396
knownRouters,
393397
this._seedRouter,
394398
currentRoutingTable,
@@ -400,7 +404,8 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
400404
return await this._applyRoutingTableIfPossible(
401405
currentRoutingTable,
402406
newRoutingTable,
403-
onDatabaseNameResolved
407+
onDatabaseNameResolved,
408+
error
404409
)
405410
}
406411

@@ -410,7 +415,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
410415
bookmarks,
411416
impersonatedUser
412417
) {
413-
const newRoutingTable = await this._fetchRoutingTable(
418+
const [newRoutingTable, error] = await this._fetchRoutingTable(
414419
knownRouters,
415420
currentRoutingTable,
416421
bookmarks,
@@ -419,7 +424,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
419424

420425
if (newRoutingTable) {
421426
// one of the known routers returned a valid routing table - use it
422-
return newRoutingTable
427+
return [newRoutingTable, null]
423428
}
424429

425430
// returned routing table was undefined, this means a connection error happened and the last known
@@ -431,7 +436,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
431436
lastRouterIndex
432437
)
433438

434-
return null
439+
return [null, error]
435440
}
436441

437442
async _fetchRoutingTableUsingSeedRouter (
@@ -460,14 +465,14 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
460465
return [].concat.apply([], dnsResolvedAddresses)
461466
}
462467

463-
_fetchRoutingTable (routerAddresses, routingTable, bookmarks, impersonatedUser) {
468+
async _fetchRoutingTable (routerAddresses, routingTable, bookmarks, impersonatedUser) {
464469
return routerAddresses.reduce(
465470
async (refreshedTablePromise, currentRouter, currentIndex) => {
466-
const newRoutingTable = await refreshedTablePromise
471+
const [newRoutingTable] = await refreshedTablePromise
467472

468473
if (newRoutingTable) {
469474
// valid routing table was fetched - just return it, try next router otherwise
470-
return newRoutingTable
475+
return [newRoutingTable, null]
471476
} else {
472477
// returned routing table was undefined, this means a connection error happened and we need to forget the
473478
// previous router and try the next one
@@ -480,19 +485,19 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
480485
}
481486

482487
// try next router
483-
const session = await this._createSessionForRediscovery(
488+
const [session, error] = await this._createSessionForRediscovery(
484489
currentRouter,
485490
bookmarks,
486491
impersonatedUser
487492
)
488493
if (session) {
489494
try {
490-
return await this._rediscovery.lookupRoutingTableOnRouter(
495+
return [await this._rediscovery.lookupRoutingTableOnRouter(
491496
session,
492497
routingTable.database,
493498
currentRouter,
494499
impersonatedUser
495-
)
500+
), null]
496501
} catch (error) {
497502
return this._handleRediscoveryError(error, currentRouter)
498503
} finally {
@@ -501,10 +506,10 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
501506
} else {
502507
// unable to acquire connection and create session towards the current router
503508
// return null to signal that the next router should be tried
504-
return null
509+
return [null, error]
505510
}
506511
},
507-
Promise.resolve(null)
512+
Promise.resolve([null, null])
508513
)
509514
}
510515

@@ -522,20 +527,20 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
522527

523528
const protocolVersion = connection.protocol().version
524529
if (protocolVersion < 4.0) {
525-
return new Session({
530+
return [new Session({
526531
mode: WRITE,
527532
bookmarks: Bookmarks.empty(),
528533
connectionProvider
529-
})
534+
}), null]
530535
}
531536

532-
return new Session({
537+
return [new Session({
533538
mode: READ,
534539
database: SYSTEM_DB_NAME,
535540
bookmarks,
536541
connectionProvider,
537542
impersonatedUser
538-
})
543+
}), null]
539544
} catch (error) {
540545
return this._handleRediscoveryError(error, routerAddress)
541546
}
@@ -548,21 +553,23 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
548553
// throw when getServers procedure not found because this is clearly a configuration issue
549554
throw newError(
550555
`Server at ${routerAddress.asHostPort()} can't perform routing. Make sure you are connecting to a causal cluster`,
551-
SERVICE_UNAVAILABLE
556+
SERVICE_UNAVAILABLE,
557+
error
552558
)
553559
}
554560
this._log.warn(
555561
`unable to fetch routing table because of an error ${error}`
556562
)
557-
return null
563+
return [null, error]
558564
}
559565

560-
async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable, onDatabaseNameResolved) {
566+
async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable, onDatabaseNameResolved, error) {
561567
if (!newRoutingTable) {
562568
// none of routing servers returned valid routing table, throw exception
563569
throw newError(
564570
`Could not perform discovery. No routing servers available. Known routing table: ${currentRoutingTable}`,
565-
SERVICE_UNAVAILABLE
571+
SERVICE_UNAVAILABLE,
572+
error
566573
)
567574
}
568575

0 commit comments

Comments
 (0)