Skip to content

Commit 7b0c9ef

Browse files
committed
Throw ServiceUnavailableException when unable to connect
Driver verifies connectivity on creation. It closes the connection pool when thread is interrupted. Previously original `IllegalStateException` from the closed pool has been propagated to the user. This commit makes connectivity verification always throw `ServiceUnavailableException`.
1 parent 97e0e2f commit 7b0c9ef

File tree

2 files changed

+65
-33
lines changed

2 files changed

+65
-33
lines changed

driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.neo4j.driver.v1.Logger;
5454
import org.neo4j.driver.v1.Logging;
5555
import org.neo4j.driver.v1.exceptions.ClientException;
56+
import org.neo4j.driver.v1.exceptions.ServiceUnavailableException;
5657

5758
import static java.lang.String.format;
5859
import static org.neo4j.driver.internal.security.SecurityPlan.insecure;
@@ -78,29 +79,12 @@ public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings r
7879

7980
ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, config );
8081

81-
try
82-
{
83-
InternalDriver driver = createDriver( uri, address, connectionPool, config, newRoutingSettings,
84-
eventExecutorGroup, securityPlan, retryLogic );
82+
InternalDriver driver = createDriver( uri, address, connectionPool, config, newRoutingSettings,
83+
eventExecutorGroup, securityPlan, retryLogic );
8584

86-
// block to verify connectivity, close connection pool if thread gets interrupted
87-
Futures.blockingGet( driver.verifyConnectivity(),
88-
() -> closeConnectionPoolOnThreadInterrupt( connectionPool, config.logging() ) );
89-
return driver;
90-
}
91-
catch ( Throwable driverError )
92-
{
93-
// we need to close the connection pool if driver creation threw exception
94-
try
95-
{
96-
Futures.blockingGet( connectionPool.close() );
97-
}
98-
catch ( Throwable closeError )
99-
{
100-
driverError.addSuppressed( closeError );
101-
}
102-
throw driverError;
103-
}
85+
verifyConnectivity( driver, connectionPool, config );
86+
87+
return driver;
10488
}
10589

10690
protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan,
@@ -126,17 +110,26 @@ private InternalDriver createDriver( URI uri, BoltServerAddress address,
126110
ConnectionPool connectionPool, Config config, RoutingSettings routingSettings,
127111
EventExecutorGroup eventExecutorGroup, SecurityPlan securityPlan, RetryLogic retryLogic )
128112
{
129-
String scheme = uri.getScheme().toLowerCase();
130-
switch ( scheme )
113+
try
131114
{
132-
case BOLT_URI_SCHEME:
133-
assertNoRoutingContext( uri, routingSettings );
134-
return createDirectDriver( address, config, securityPlan, retryLogic, connectionPool );
135-
case BOLT_ROUTING_URI_SCHEME:
136-
return createRoutingDriver( address, connectionPool, config, routingSettings, securityPlan, retryLogic,
137-
eventExecutorGroup );
138-
default:
139-
throw new ClientException( format( "Unsupported URI scheme: %s", scheme ) );
115+
String scheme = uri.getScheme().toLowerCase();
116+
switch ( scheme )
117+
{
118+
case BOLT_URI_SCHEME:
119+
assertNoRoutingContext( uri, routingSettings );
120+
return createDirectDriver( address, config, securityPlan, retryLogic, connectionPool );
121+
case BOLT_ROUTING_URI_SCHEME:
122+
return createRoutingDriver( address, connectionPool, config, routingSettings, securityPlan, retryLogic,
123+
eventExecutorGroup );
124+
default:
125+
throw new ClientException( format( "Unsupported URI scheme: %s", scheme ) );
126+
}
127+
}
128+
catch ( Throwable driverError )
129+
{
130+
// we need to close the connection pool if driver creation threw exception
131+
closeConnectionPoolAndSuppressError( connectionPool, driverError );
132+
throw driverError;
140133
}
141134
}
142135

@@ -317,6 +310,45 @@ private static void assertNoRoutingContext( URI uri, RoutingSettings routingSett
317310
}
318311
}
319312

313+
private static void verifyConnectivity( InternalDriver driver, ConnectionPool connectionPool, Config config )
314+
{
315+
try
316+
{
317+
// block to verify connectivity, close connection pool if thread gets interrupted
318+
Futures.blockingGet( driver.verifyConnectivity(),
319+
() -> closeConnectionPoolOnThreadInterrupt( connectionPool, config.logging() ) );
320+
}
321+
catch ( Throwable connectionError )
322+
{
323+
if ( Thread.currentThread().isInterrupted() )
324+
{
325+
// current thread has been interrupted while verifying connectivity
326+
// connection pool should've been closed
327+
throw new ServiceUnavailableException( "Unable to create driver. Thread has been interrupted.",
328+
connectionError );
329+
}
330+
331+
// we need to close the connection pool if driver creation threw exception
332+
closeConnectionPoolAndSuppressError( connectionPool, connectionError );
333+
throw connectionError;
334+
}
335+
}
336+
337+
private static void closeConnectionPoolAndSuppressError( ConnectionPool connectionPool, Throwable mainError )
338+
{
339+
try
340+
{
341+
Futures.blockingGet( connectionPool.close() );
342+
}
343+
catch ( Throwable closeError )
344+
{
345+
if ( mainError != closeError )
346+
{
347+
mainError.addSuppressed( closeError );
348+
}
349+
}
350+
}
351+
320352
private static void closeConnectionPoolOnThreadInterrupt( ConnectionPool pool, Logging logging )
321353
{
322354
Logger log = logging.getLog( Driver.class.getSimpleName() );

driver/src/test/java/org/neo4j/driver/v1/GraphDatabaseTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public void shouldRespondToInterruptsWhenConnectingToUnresponsiveServer() throws
171171
GraphDatabase.driver( "bolt://localhost:" + serverSocket.getLocalPort() );
172172
fail( "Exception expected" );
173173
}
174-
catch ( Exception ignore )
174+
catch ( ServiceUnavailableException ignore )
175175
{
176176
// expected
177177
}

0 commit comments

Comments
 (0)