Skip to content

Fixed Bug:- Multi-Driver Failover when one of multiple hosts down#282

Merged
transistive merged 11 commits into
mainfrom
bugfix/connection-failure-multi-host
Mar 30, 2026
Merged

Fixed Bug:- Multi-Driver Failover when one of multiple hosts down#282
transistive merged 11 commits into
mainfrom
bugfix/connection-failure-multi-host

Conversation

@p123-stack
Copy link
Copy Markdown
Collaborator

Multi-Driver Failover When Primary Node Is Down

Failover Handling Implementation

  • Added support for failover when the highest-priority Neo4j driver is unavailable.

  • DriverSetupManager now continues to next available driver instead of failing immediately.

Exception Handling Improvements

  • Neo4jConnectionPool::acquire() now throws ConnectionPoolException instead of RuntimeException.

  • Neo4jDriver::verifyConnectivity() catches both ConnectException and RuntimeException.

  • Defensive try-catch added in DriverSetupManager::getDriver() to log and skip failed drivers.

Routing & Connectivity

  • Client properly attempts secondary drivers when primary fails.

  • Connection pool and driver retry logic updated to ensure uninterrupted operations.

Testing & Compliance

  • Unit tests added in MultiDriverFailoverTest and ClientExceptionHandlingTest.

  • Tests verify driver fallback, client-level transactions, and complete failover flow.


$client = new Client($driverSetupManager, $sessionConfig, $transactionConfig);

$this->expectException(RuntimeException::class);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@p123-stack, I am missing the test where we are testing what happens during a connection exception when statements are being run.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added tests where runStatements throws ConnectionPoolException (retry + resetDriver). Say if you also want one with ConnectException explicitly.

Copy link
Copy Markdown
Collaborator

@transistive transistive left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there! Good stuff. We can probably simplify some of the tests to get the same amount of coverage, and we can have a simple solution by adding reset logic to the driver setup manager

$successfulSessionMock->method('runStatements')
->willReturn($expectedResult);

$driverSetupManager->expects($this->exactly(2))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see here that this won't work perfectly. You are mocking the driver setup manager to return different drivers on subsequent calls, that is not how the driver setup manager operates. It will always return the same driver

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — we implemented resetDriver on DriverSetupManager and call it from executeWithRetry before retry, so getDriver isn’t expected to “rotate” by itself. Tests now include one that asserts resetDriver + retry.

Comment thread src/Client.php
@p123-stack p123-stack marked this pull request as ready for review March 9, 2026 12:35
@zorac
Copy link
Copy Markdown
Contributor

zorac commented Mar 18, 2026

Looks like this should fix #281 - thanks!

{
public function testClientRunStatementWithFailingDriver(): void
{
$driverSetupManager = $this->createMock(DriverSetupManager::class);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have to improve testing here to see if the recovery works

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added unit tests that exercise the retry path: after a ConnectionPoolException, resetDriver is called and the next getDriver succeeds for writeTransaction, readTransaction, and beginTransaction. run / runStatements retry behavior was already covered in ClientSessionExceptionHandlingTest. Resolving—let me know if you want an integration-style test as well.

…in verifyConnectivity and test client recovery
Resolve RoutingTable: combine hasServer (in_array) with removeServer returning self when unchanged.

Made-with: Cursor
@transistive transistive merged commit 8a76b7a into main Mar 30, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants