@@ -23,18 +23,20 @@ import Session from '../session';
2323import RoundRobinArray from './round-robin-array' ;
2424import RoutingTable from './routing-table' ;
2525import Rediscovery from './rediscovery' ;
26+ import hasFeature from './features' ;
27+ import { DnsHostNameResolver , DummyHostNameResolver } from './host-name-resolvers' ;
2628
2729class ConnectionProvider {
2830
2931 acquireConnection ( mode ) {
30- throw new Error ( 'Abstract method ' ) ;
32+ throw new Error ( 'Abstract function ' ) ;
3133 }
3234
3335 _withAdditionalOnErrorCallback ( connectionPromise , driverOnErrorCallback ) {
3436 // install error handler from the driver on the connection promise; this callback is installed separately
3537 // so that it does not handle errors, instead it is just an additional error reporting facility.
3638 connectionPromise . catch ( error => {
37- driverOnErrorCallback ( error )
39+ driverOnErrorCallback ( error ) ;
3840 } ) ;
3941 // return the original connection promise
4042 return connectionPromise ;
@@ -61,10 +63,12 @@ export class LoadBalancer extends ConnectionProvider {
6163
6264 constructor ( address , connectionPool , driverOnErrorCallback ) {
6365 super ( ) ;
64- this . _routingTable = new RoutingTable ( new RoundRobinArray ( [ address ] ) ) ;
66+ this . _seedRouter = address ;
67+ this . _routingTable = new RoutingTable ( new RoundRobinArray ( [ this . _seedRouter ] ) ) ;
6568 this . _rediscovery = new Rediscovery ( ) ;
6669 this . _connectionPool = connectionPool ;
6770 this . _driverOnErrorCallback = driverOnErrorCallback ;
71+ this . _hostNameResolver = LoadBalancer . _createHostNameResolver ( ) ;
6872 }
6973
7074 acquireConnection ( mode ) {
@@ -109,7 +113,42 @@ export class LoadBalancer extends ConnectionProvider {
109113 _refreshRoutingTable ( currentRoutingTable ) {
110114 const knownRouters = currentRoutingTable . routers . toArray ( ) ;
111115
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 ) => {
113152 return refreshedTablePromise . then ( newRoutingTable => {
114153 if ( newRoutingTable ) {
115154 if ( ! newRoutingTable . writers . isEmpty ( ) ) {
@@ -120,28 +159,14 @@ export class LoadBalancer extends ConnectionProvider {
120159 // returned routing table was undefined, this means a connection error happened and we need to forget the
121160 // previous router and try the next one
122161 const previousRouterIndex = currentIndex - 1 ;
123- this . _forgetRouter ( currentRoutingTable , knownRouters , previousRouterIndex ) ;
162+ LoadBalancer . _forgetRouter ( routingTable , routerAddresses , previousRouterIndex ) ;
124163 }
125164
126165 // try next router
127166 const session = this . _createSessionForRediscovery ( currentRouter ) ;
128167 return this . _rediscovery . lookupRoutingTableOnRouter ( session , currentRouter ) ;
129168 } ) ;
130169 } , 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- } ) ;
145170 }
146171
147172 _createSessionForRediscovery ( routerAddress ) {
@@ -162,12 +187,23 @@ export class LoadBalancer extends ConnectionProvider {
162187 this . _routingTable = newRoutingTable ;
163188 }
164189
165- _forgetRouter ( routingTable , routersArray , routerIndex ) {
190+ static _isValidRoutingTable ( routingTable ) {
191+ return routingTable && ! routingTable . writers . isEmpty ( ) ;
192+ }
193+
194+ static _forgetRouter ( routingTable , routersArray , routerIndex ) {
166195 const address = routersArray [ routerIndex ] ;
167- if ( address ) {
196+ if ( routingTable && address ) {
168197 routingTable . forgetRouter ( address ) ;
169198 }
170199 }
200+
201+ static _createHostNameResolver ( ) {
202+ if ( hasFeature ( 'dns_lookup' ) ) {
203+ return new DnsHostNameResolver ( ) ;
204+ }
205+ return new DummyHostNameResolver ( ) ;
206+ }
171207}
172208
173209export class SingleConnectionProvider extends ConnectionProvider {
0 commit comments