Skip to content

Add support for error cause in Neo4jError and Routing errors #960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
this.forgetWriter(address, database || DEFAULT_DB_NAME)
return newError(
'No longer possible to write to server at ' + address,
SESSION_EXPIRED
SESSION_EXPIRED,
error
)
}

Expand Down Expand Up @@ -338,7 +339,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
) {
// we start with seed router, no routers were probed before
const seenRouters = []
let newRoutingTable = await this._fetchRoutingTableUsingSeedRouter(
let [newRoutingTable, error] = await this._fetchRoutingTableUsingSeedRouter(
seenRouters,
this._seedRouter,
currentRoutingTable,
Expand All @@ -350,18 +351,21 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
this._useSeedRouter = false
} else {
// seed router did not return a valid routing table - try to use other known routers
newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
const [newRoutingTable2, error2] = await this._fetchRoutingTableUsingKnownRouters(
knownRouters,
currentRoutingTable,
bookmarks,
impersonatedUser
)
newRoutingTable = newRoutingTable2
error = error2 || error
}

return await this._applyRoutingTableIfPossible(
currentRoutingTable,
newRoutingTable,
onDatabaseNameResolved
onDatabaseNameResolved,
error
)
}

Expand All @@ -372,7 +376,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
impersonatedUser,
onDatabaseNameResolved
) {
let newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
let [newRoutingTable, error] = await this._fetchRoutingTableUsingKnownRouters(
knownRouters,
currentRoutingTable,
bookmarks,
Expand All @@ -381,7 +385,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider

if (!newRoutingTable) {
// none of the known routers returned a valid routing table - try to use seed router address for rediscovery
newRoutingTable = await this._fetchRoutingTableUsingSeedRouter(
[newRoutingTable, error] = await this._fetchRoutingTableUsingSeedRouter(
knownRouters,
this._seedRouter,
currentRoutingTable,
Expand All @@ -393,7 +397,8 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
return await this._applyRoutingTableIfPossible(
currentRoutingTable,
newRoutingTable,
onDatabaseNameResolved
onDatabaseNameResolved,
error
)
}

Expand All @@ -403,7 +408,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
bookmarks,
impersonatedUser
) {
const newRoutingTable = await this._fetchRoutingTable(
const [newRoutingTable, error] = await this._fetchRoutingTable(
knownRouters,
currentRoutingTable,
bookmarks,
Expand All @@ -412,7 +417,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider

if (newRoutingTable) {
// one of the known routers returned a valid routing table - use it
return newRoutingTable
return [newRoutingTable, null]
}

// returned routing table was undefined, this means a connection error happened and the last known
Expand All @@ -424,7 +429,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
lastRouterIndex
)

return null
return [null, error]
}

async _fetchRoutingTableUsingSeedRouter (
Expand Down Expand Up @@ -453,14 +458,14 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
return [].concat.apply([], dnsResolvedAddresses)
}

_fetchRoutingTable (routerAddresses, routingTable, bookmarks, impersonatedUser) {
async _fetchRoutingTable (routerAddresses, routingTable, bookmarks, impersonatedUser) {
return routerAddresses.reduce(
async (refreshedTablePromise, currentRouter, currentIndex) => {
const newRoutingTable = await refreshedTablePromise
const [newRoutingTable] = await refreshedTablePromise

if (newRoutingTable) {
// valid routing table was fetched - just return it, try next router otherwise
return newRoutingTable
return [newRoutingTable, null]
} else {
// returned routing table was undefined, this means a connection error happened and we need to forget the
// previous router and try the next one
Expand All @@ -473,19 +478,19 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
}

// try next router
const session = await this._createSessionForRediscovery(
const [session, error] = await this._createSessionForRediscovery(
currentRouter,
bookmarks,
impersonatedUser
)
if (session) {
try {
return await this._rediscovery.lookupRoutingTableOnRouter(
return [await this._rediscovery.lookupRoutingTableOnRouter(
session,
routingTable.database,
currentRouter,
impersonatedUser
)
), null]
} catch (error) {
return this._handleRediscoveryError(error, currentRouter)
} finally {
Expand All @@ -494,10 +499,10 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
} else {
// unable to acquire connection and create session towards the current router
// return null to signal that the next router should be tried
return null
return [null, error]
}
},
Promise.resolve(null)
Promise.resolve([null, null])
)
}

Expand All @@ -515,20 +520,20 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider

const protocolVersion = connection.protocol().version
if (protocolVersion < 4.0) {
return new Session({
return [new Session({
mode: WRITE,
bookmarks: Bookmarks.empty(),
connectionProvider
})
}), null]
}

return new Session({
return [new Session({
mode: READ,
database: SYSTEM_DB_NAME,
bookmarks,
connectionProvider,
impersonatedUser
})
}), null]
} catch (error) {
return this._handleRediscoveryError(error, routerAddress)
}
Expand All @@ -541,21 +546,23 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
// throw when getServers procedure not found because this is clearly a configuration issue
throw newError(
`Server at ${routerAddress.asHostPort()} can't perform routing. Make sure you are connecting to a causal cluster`,
SERVICE_UNAVAILABLE
SERVICE_UNAVAILABLE,
error
)
}
this._log.warn(
`unable to fetch routing table because of an error ${error}`
)
return null
return [null, error]
}

async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable, onDatabaseNameResolved) {
async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable, onDatabaseNameResolved, error) {
if (!newRoutingTable) {
// none of routing servers returned valid routing table, throw exception
throw newError(
`Could not perform discovery. No routing servers available. Known routing table: ${currentRoutingTable}`,
SERVICE_UNAVAILABLE
SERVICE_UNAVAILABLE,
error
)
}

Expand Down
Loading