@@ -23,18 +23,20 @@ import Session from '../session';
23
23
import RoundRobinArray from './round-robin-array' ;
24
24
import RoutingTable from './routing-table' ;
25
25
import Rediscovery from './rediscovery' ;
26
+ import hasFeature from './features' ;
27
+ import { DnsHostNameResolver , DummyHostNameResolver } from './host-name-resolvers' ;
26
28
27
29
class ConnectionProvider {
28
30
29
31
acquireConnection ( mode ) {
30
- throw new Error ( 'Abstract method ' ) ;
32
+ throw new Error ( 'Abstract function ' ) ;
31
33
}
32
34
33
35
_withAdditionalOnErrorCallback ( connectionPromise , driverOnErrorCallback ) {
34
36
// install error handler from the driver on the connection promise; this callback is installed separately
35
37
// so that it does not handle errors, instead it is just an additional error reporting facility.
36
38
connectionPromise . catch ( error => {
37
- driverOnErrorCallback ( error )
39
+ driverOnErrorCallback ( error ) ;
38
40
} ) ;
39
41
// return the original connection promise
40
42
return connectionPromise ;
@@ -61,10 +63,12 @@ export class LoadBalancer extends ConnectionProvider {
61
63
62
64
constructor ( address , connectionPool , driverOnErrorCallback ) {
63
65
super ( ) ;
64
- this . _routingTable = new RoutingTable ( new RoundRobinArray ( [ address ] ) ) ;
66
+ this . _seedRouter = address ;
67
+ this . _routingTable = new RoutingTable ( new RoundRobinArray ( [ this . _seedRouter ] ) ) ;
65
68
this . _rediscovery = new Rediscovery ( ) ;
66
69
this . _connectionPool = connectionPool ;
67
70
this . _driverOnErrorCallback = driverOnErrorCallback ;
71
+ this . _hostNameResolver = LoadBalancer . _createHostNameResolver ( ) ;
68
72
}
69
73
70
74
acquireConnection ( mode ) {
@@ -109,7 +113,42 @@ export class LoadBalancer extends ConnectionProvider {
109
113
_refreshRoutingTable ( currentRoutingTable ) {
110
114
const knownRouters = currentRoutingTable . routers . toArray ( ) ;
111
115
112
- const refreshedTablePromise = knownRouters . reduce ( ( refreshedTablePromise , currentRouter , currentIndex ) => {
116
+ return this . _fetchNewRoutingTable ( knownRouters , currentRoutingTable ) . then ( newRoutingTable => {
117
+ if ( LoadBalancer . _isValidRoutingTable ( newRoutingTable ) ) {
118
+ // one of the known routers returned a valid routing table - use it
119
+ return newRoutingTable ;
120
+ }
121
+
122
+ if ( ! newRoutingTable ) {
123
+ // returned routing table was undefined, this means a connection error happened and the last known
124
+ // router did not return a valid routing table, so we need to forget it
125
+ const lastRouterIndex = knownRouters . length - 1 ;
126
+ LoadBalancer . _forgetRouter ( currentRoutingTable , knownRouters , lastRouterIndex ) ;
127
+ }
128
+
129
+ // none of the known routers returned a valid routing table - try to use seed router address for rediscovery
130
+ return this . _fetchNewRoutingTableUsingSeedRouterAddress ( knownRouters , this . _seedRouter ) ;
131
+ } ) . then ( newRoutingTable => {
132
+ if ( LoadBalancer . _isValidRoutingTable ( newRoutingTable ) ) {
133
+ this . _updateRoutingTable ( newRoutingTable ) ;
134
+ return newRoutingTable ;
135
+ }
136
+
137
+ // none of the existing routers returned valid routing table, throw exception
138
+ throw newError ( 'Could not perform discovery. No routing servers available.' , SERVICE_UNAVAILABLE ) ;
139
+ } ) ;
140
+ }
141
+
142
+ _fetchNewRoutingTableUsingSeedRouterAddress ( knownRouters , seedRouter ) {
143
+ return this . _hostNameResolver . resolve ( seedRouter ) . then ( resolvedRouterAddresses => {
144
+ // filter out all addresses that we've already tried
145
+ const newAddresses = resolvedRouterAddresses . filter ( address => knownRouters . indexOf ( address ) < 0 ) ;
146
+ return this . _fetchNewRoutingTable ( newAddresses , null ) ;
147
+ } ) ;
148
+ }
149
+
150
+ _fetchNewRoutingTable ( routerAddresses , routingTable ) {
151
+ return routerAddresses . reduce ( ( refreshedTablePromise , currentRouter , currentIndex ) => {
113
152
return refreshedTablePromise . then ( newRoutingTable => {
114
153
if ( newRoutingTable ) {
115
154
if ( ! newRoutingTable . writers . isEmpty ( ) ) {
@@ -120,28 +159,14 @@ export class LoadBalancer extends ConnectionProvider {
120
159
// returned routing table was undefined, this means a connection error happened and we need to forget the
121
160
// previous router and try the next one
122
161
const previousRouterIndex = currentIndex - 1 ;
123
- this . _forgetRouter ( currentRoutingTable , knownRouters , previousRouterIndex ) ;
162
+ LoadBalancer . _forgetRouter ( routingTable , routerAddresses , previousRouterIndex ) ;
124
163
}
125
164
126
165
// try next router
127
166
const session = this . _createSessionForRediscovery ( currentRouter ) ;
128
167
return this . _rediscovery . lookupRoutingTableOnRouter ( session , currentRouter ) ;
129
168
} ) ;
130
169
} , Promise . resolve ( null ) ) ;
131
-
132
- return refreshedTablePromise . then ( newRoutingTable => {
133
- if ( newRoutingTable && ! newRoutingTable . writers . isEmpty ( ) ) {
134
- this . _updateRoutingTable ( newRoutingTable ) ;
135
- return newRoutingTable ;
136
- }
137
-
138
- // forget the last known router because it did not return a valid routing table
139
- const lastRouterIndex = knownRouters . length - 1 ;
140
- this . _forgetRouter ( currentRoutingTable , knownRouters , lastRouterIndex ) ;
141
-
142
- // none of the existing routers returned valid routing table, throw exception
143
- throw newError ( 'Could not perform discovery. No routing servers available.' , SERVICE_UNAVAILABLE ) ;
144
- } ) ;
145
170
}
146
171
147
172
_createSessionForRediscovery ( routerAddress ) {
@@ -162,12 +187,23 @@ export class LoadBalancer extends ConnectionProvider {
162
187
this . _routingTable = newRoutingTable ;
163
188
}
164
189
165
- _forgetRouter ( routingTable , routersArray , routerIndex ) {
190
+ static _isValidRoutingTable ( routingTable ) {
191
+ return routingTable && ! routingTable . writers . isEmpty ( ) ;
192
+ }
193
+
194
+ static _forgetRouter ( routingTable , routersArray , routerIndex ) {
166
195
const address = routersArray [ routerIndex ] ;
167
- if ( address ) {
196
+ if ( routingTable && address ) {
168
197
routingTable . forgetRouter ( address ) ;
169
198
}
170
199
}
200
+
201
+ static _createHostNameResolver ( ) {
202
+ if ( hasFeature ( 'dns_lookup' ) ) {
203
+ return new DnsHostNameResolver ( ) ;
204
+ }
205
+ return new DummyHostNameResolver ( ) ;
206
+ }
171
207
}
172
208
173
209
export class SingleConnectionProvider extends ConnectionProvider {
0 commit comments