32
32
33
33
import org .neo4j .driver .Bookmark ;
34
34
import org .neo4j .driver .Logger ;
35
+ import org .neo4j .driver .exceptions .DiscoveryException ;
35
36
import org .neo4j .driver .exceptions .FatalDiscoveryException ;
36
37
import org .neo4j .driver .exceptions .SecurityException ;
37
38
import org .neo4j .driver .exceptions .ServiceUnavailableException ;
55
56
public class RediscoveryImpl implements Rediscovery
56
57
{
57
58
private static final String NO_ROUTERS_AVAILABLE = "Could not perform discovery for database '%s'. No routing server available." ;
59
+ private static final String RECOVERABLE_ROUTING_ERROR = "Failed to update routing table with server '%s'." ;
58
60
59
61
private final BoltServerAddress initialRouter ;
60
62
private final RoutingSettings settings ;
@@ -86,14 +88,16 @@ public RediscoveryImpl( BoltServerAddress initialRouter, RoutingSettings setting
86
88
public CompletionStage <ClusterComposition > lookupClusterComposition ( RoutingTable routingTable , ConnectionPool connectionPool , Bookmark bookmark )
87
89
{
88
90
CompletableFuture <ClusterComposition > result = new CompletableFuture <>();
89
- lookupClusterComposition ( routingTable , connectionPool , 0 , 0 , result , bookmark );
91
+ // if we failed discovery, we will chain all errors into this one.
92
+ ServiceUnavailableException baseError = new ServiceUnavailableException ( NO_ROUTERS_AVAILABLE );
93
+ lookupClusterComposition ( routingTable , connectionPool , 0 , 0 , result , bookmark , baseError );
90
94
return result ;
91
95
}
92
96
93
97
private void lookupClusterComposition ( RoutingTable routingTable , ConnectionPool pool ,
94
- int failures , long previousDelay , CompletableFuture <ClusterComposition > result , Bookmark bookmark )
98
+ int failures , long previousDelay , CompletableFuture <ClusterComposition > result , Bookmark bookmark , Throwable baseError )
95
99
{
96
- lookup ( routingTable , pool , bookmark ).whenComplete ( ( composition , completionError ) ->
100
+ lookup ( routingTable , pool , bookmark , baseError ).whenComplete ( ( composition , completionError ) ->
97
101
{
98
102
Throwable error = Futures .completionExceptionCause ( completionError );
99
103
if ( error != null )
@@ -109,67 +113,68 @@ else if ( composition != null )
109
113
int newFailures = failures + 1 ;
110
114
if ( newFailures >= settings .maxRoutingFailures () )
111
115
{
112
- result .completeExceptionally ( new ServiceUnavailableException ( String .format ( NO_ROUTERS_AVAILABLE , routingTable .database ().description () ) ) );
116
+ // now we throw our saved error out
117
+ result .completeExceptionally ( baseError );
113
118
}
114
119
else
115
120
{
116
121
long nextDelay = Math .max ( settings .retryTimeoutDelay (), previousDelay * 2 );
117
122
logger .info ( "Unable to fetch new routing table, will try again in " + nextDelay + "ms" );
118
123
eventExecutorGroup .next ().schedule (
119
- () -> lookupClusterComposition ( routingTable , pool , newFailures , nextDelay , result , bookmark ),
124
+ () -> lookupClusterComposition ( routingTable , pool , newFailures , nextDelay , result , bookmark , baseError ),
120
125
nextDelay , TimeUnit .MILLISECONDS
121
126
);
122
127
}
123
128
}
124
129
} );
125
130
}
126
131
127
- private CompletionStage <ClusterComposition > lookup ( RoutingTable routingTable , ConnectionPool connectionPool , Bookmark bookmark )
132
+ private CompletionStage <ClusterComposition > lookup ( RoutingTable routingTable , ConnectionPool connectionPool , Bookmark bookmark , Throwable baseError )
128
133
{
129
134
CompletionStage <ClusterComposition > compositionStage ;
130
135
131
136
if ( routingTable .preferInitialRouter () )
132
137
{
133
- compositionStage = lookupOnInitialRouterThenOnKnownRouters ( routingTable , connectionPool , bookmark );
138
+ compositionStage = lookupOnInitialRouterThenOnKnownRouters ( routingTable , connectionPool , bookmark , baseError );
134
139
}
135
140
else
136
141
{
137
- compositionStage = lookupOnKnownRoutersThenOnInitialRouter ( routingTable , connectionPool , bookmark );
142
+ compositionStage = lookupOnKnownRoutersThenOnInitialRouter ( routingTable , connectionPool , bookmark , baseError );
138
143
}
139
144
140
145
return compositionStage ;
141
146
}
142
147
143
- private CompletionStage <ClusterComposition > lookupOnKnownRoutersThenOnInitialRouter ( RoutingTable routingTable ,
144
- ConnectionPool connectionPool , Bookmark bookmark )
148
+ private CompletionStage <ClusterComposition > lookupOnKnownRoutersThenOnInitialRouter ( RoutingTable routingTable , ConnectionPool connectionPool ,
149
+ Bookmark bookmark , Throwable baseError )
145
150
{
146
151
Set <BoltServerAddress > seenServers = new HashSet <>();
147
- return lookupOnKnownRouters ( routingTable , connectionPool , seenServers , bookmark ).thenCompose ( composition ->
152
+ return lookupOnKnownRouters ( routingTable , connectionPool , seenServers , bookmark , baseError ).thenCompose ( composition ->
148
153
{
149
154
if ( composition != null )
150
155
{
151
156
return completedFuture ( composition );
152
157
}
153
- return lookupOnInitialRouter ( routingTable , connectionPool , seenServers , bookmark );
158
+ return lookupOnInitialRouter ( routingTable , connectionPool , seenServers , bookmark , baseError );
154
159
} );
155
160
}
156
161
157
162
private CompletionStage <ClusterComposition > lookupOnInitialRouterThenOnKnownRouters ( RoutingTable routingTable ,
158
- ConnectionPool connectionPool , Bookmark bookmark )
163
+ ConnectionPool connectionPool , Bookmark bookmark , Throwable baseError )
159
164
{
160
165
Set <BoltServerAddress > seenServers = emptySet ();
161
- return lookupOnInitialRouter ( routingTable , connectionPool , seenServers , bookmark ).thenCompose ( composition ->
166
+ return lookupOnInitialRouter ( routingTable , connectionPool , seenServers , bookmark , baseError ).thenCompose ( composition ->
162
167
{
163
168
if ( composition != null )
164
169
{
165
170
return completedFuture ( composition );
166
171
}
167
- return lookupOnKnownRouters ( routingTable , connectionPool , new HashSet <>(), bookmark );
172
+ return lookupOnKnownRouters ( routingTable , connectionPool , new HashSet <>(), bookmark , baseError );
168
173
} );
169
174
}
170
175
171
- private CompletionStage <ClusterComposition > lookupOnKnownRouters ( RoutingTable routingTable ,
172
- ConnectionPool connectionPool , Set < BoltServerAddress > seenServers , Bookmark bookmark )
176
+ private CompletionStage <ClusterComposition > lookupOnKnownRouters ( RoutingTable routingTable , ConnectionPool connectionPool , Set < BoltServerAddress > seenServers , Bookmark bookmark ,
177
+ Throwable baseError )
173
178
{
174
179
BoltServerAddress [] addresses = routingTable .routers ().toArray ();
175
180
@@ -184,16 +189,16 @@ private CompletionStage<ClusterComposition> lookupOnKnownRouters( RoutingTable r
184
189
}
185
190
else
186
191
{
187
- return lookupOnRouter ( address , routingTable , connectionPool , bookmark )
192
+ return lookupOnRouter ( address , routingTable , connectionPool , bookmark , baseError )
188
193
.whenComplete ( ( ignore , error ) -> seenServers .add ( address ) );
189
194
}
190
195
} );
191
196
}
192
197
return result ;
193
198
}
194
199
195
- private CompletionStage <ClusterComposition > lookupOnInitialRouter ( RoutingTable routingTable ,
196
- ConnectionPool connectionPool , Set < BoltServerAddress > seenServers , Bookmark bookmark )
200
+ private CompletionStage <ClusterComposition > lookupOnInitialRouter ( RoutingTable routingTable , ConnectionPool connectionPool , Set < BoltServerAddress > seenServers , Bookmark bookmark ,
201
+ Throwable baseError )
197
202
{
198
203
List <BoltServerAddress > addresses ;
199
204
try
@@ -215,14 +220,14 @@ private CompletionStage<ClusterComposition> lookupOnInitialRouter( RoutingTable
215
220
{
216
221
return completedFuture ( composition );
217
222
}
218
- return lookupOnRouter ( address , routingTable , connectionPool , bookmark );
223
+ return lookupOnRouter ( address , routingTable , connectionPool , bookmark , baseError );
219
224
} );
220
225
}
221
226
return result ;
222
227
}
223
228
224
229
private CompletionStage <ClusterComposition > lookupOnRouter ( BoltServerAddress routerAddress ,
225
- RoutingTable routingTable , ConnectionPool connectionPool , Bookmark bookmark )
230
+ RoutingTable routingTable , ConnectionPool connectionPool , Bookmark bookmark , Throwable baseError )
226
231
{
227
232
CompletionStage <Connection > connectionStage = connectionPool .acquire ( routerAddress );
228
233
@@ -232,7 +237,7 @@ private CompletionStage<ClusterComposition> lookupOnRouter( BoltServerAddress ro
232
237
Throwable cause = Futures .completionExceptionCause ( error );
233
238
if ( cause != null )
234
239
{
235
- return handleRoutingProcedureError ( cause , routingTable , routerAddress );
240
+ return handleRoutingProcedureError ( cause , routingTable , routerAddress , baseError );
236
241
}
237
242
else
238
243
{
@@ -242,7 +247,7 @@ private CompletionStage<ClusterComposition> lookupOnRouter( BoltServerAddress ro
242
247
}
243
248
244
249
private ClusterComposition handleRoutingProcedureError ( Throwable error , RoutingTable routingTable ,
245
- BoltServerAddress routerAddress )
250
+ BoltServerAddress routerAddress , Throwable baseError )
246
251
{
247
252
if ( error instanceof SecurityException || error instanceof FatalDiscoveryException )
248
253
{
@@ -251,7 +256,10 @@ private ClusterComposition handleRoutingProcedureError( Throwable error, Routing
251
256
}
252
257
253
258
// Retriable error happened during discovery.
254
- logger .warn ( format ( "Failed to update routing table with server '%s'." , routerAddress ), error );
259
+ DiscoveryException discoveryError = new DiscoveryException ( format ( RECOVERABLE_ROUTING_ERROR , routerAddress ), error );
260
+ Futures .combineErrors ( baseError , discoveryError ); // we record each failure here
261
+ logger .warn ( format ( "Received a recoverable discovery error with server '%s', will continue discovery with other routing servers if available." ,
262
+ routerAddress ), discoveryError );
255
263
routingTable .forget ( routerAddress );
256
264
return null ;
257
265
}
0 commit comments