17
17
import { HostInfo } from "../../host_info" ;
18
18
import { CacheMap } from "../../utils/cache_map" ;
19
19
import { PluginService } from "../../plugin_service" ;
20
- import { HostListProviderService } from "../../host_list_provider_service" ;
21
20
import { HostAvailability } from "../../host_availability/host_availability" ;
22
21
import { logTopology , sleep } from "../../utils/utils" ;
23
22
import { logger } from "../../../logutils" ;
24
23
import { HostRole } from "../../host_role" ;
25
24
import { ClientWrapper } from "../../client_wrapper" ;
26
- import { Messages } from "../../utils/messages" ;
27
- import { TopologyAwareDatabaseDialect } from "../../topology_aware_database_dialect" ;
28
- import { HostListProvider } from "../host_list_provider" ;
29
25
import { AwsWrapperError } from "../../utils/errors" ;
26
+ import { MonitoringRdsHostListProvider } from "./monitoring_host_list_provider" ;
30
27
31
28
export interface ClusterToplogyMonitor {
32
29
forceRefresh ( client : any , timeoutMs : number ) : Promise < HostInfo [ ] > ;
33
30
34
- setClusterId ( clusterId : string ) : void ;
35
-
36
31
close ( ) : void ;
37
32
38
33
forceMonitoringRefresh ( shouldVerifyWriter : boolean , timeoutMs : number ) : Promise < HostInfo [ ] > ;
39
34
}
40
35
41
36
export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
42
- public clusterId : string ;
43
- public topologyMap : CacheMap < string , HostInfo [ ] > ;
44
- private topologyCacheExpirationNanos : number = 10000 ; // TODO: investigate values and set in constructor.
45
- protected initialHostInfo : HostInfo ;
46
- public properties : Map < string , any > ;
47
- public pluginService : PluginService ;
48
- protected hostListProviderService : HostListProviderService ;
49
- private hostListProvider : HostListProvider ;
50
- protected refreshRate : number = 300 ; // TODO: investigate issues with setting lower values.
51
- private highRefreshRate : number = 300 ;
37
+ static readonly TOPOLOGY_CACHE_EXPIRATION_MS : number = 300000 ;
38
+
39
+ private readonly clusterId : string ;
40
+ private readonly initialHostInfo : HostInfo ;
41
+ private readonly _properties : Map < string , any > ;
42
+ private readonly _pluginService : PluginService ;
43
+ private readonly _hostListProvider : MonitoringRdsHostListProvider ;
44
+ private readonly refreshRateMs : number ;
45
+ private readonly highRefreshRateMs : number ;
52
46
47
+ private topologyMap : CacheMap < string , HostInfo [ ] > ;
53
48
private writerHostInfo : HostInfo = null ;
54
49
private isVerifiedWriterConnection : boolean = false ;
55
50
private monitoringClient : ClientWrapper = null ;
56
- private highRefreshRateEndTime : any = 0 ;
57
- private highRefreshPeriodAfterPanic : number = 30000 ; // 30 seconds.
58
- private ignoreTopologyRequest : number = 1000 ; // 10 seconds.
51
+ private highRefreshRateEndTime : number = 0 ;
52
+ private highRefreshPeriodAfterPanicMs : number = 30000 ; // 30 seconds.
59
53
private ignoreNewTopologyRequestsEndTime : number = 0 ;
54
+ private ignoreTopologyRequestMs : number = 10000 ; // 10 seconds.
60
55
61
56
// Controls for stopping the ClusterTopologyMonitor run.
62
57
private stopMonitoring : boolean = false ;
63
- private runPromise : Promise < void > ;
58
+ private readonly runPromise : Promise < void > ;
64
59
65
60
// Tracking of the host monitors.
66
61
private hostMonitors : Map < string , HostMonitor > = new Map ( ) ;
@@ -87,20 +82,29 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
87
82
initialHostSpec : HostInfo ,
88
83
props ,
89
84
pluginService : PluginService ,
90
- hostListProviderService : HostListProviderService ,
91
- hostListProvider : HostListProvider ,
92
- refreshRateNano
85
+ hostListProvider : MonitoringRdsHostListProvider ,
86
+ refreshRateMs : number ,
87
+ highRefreshRateMs : number
93
88
) {
94
89
this . clusterId = clusterId ;
95
90
this . topologyMap = topologyMap ;
96
91
this . initialHostInfo = initialHostSpec ;
97
- this . pluginService = pluginService ;
98
- this . hostListProviderService = hostListProviderService ;
99
- this . hostListProvider = hostListProvider ;
100
- this . properties = props ;
101
- //this.refreshRateNano = refreshRateNano; // TODO: coordinate timeouts for bigint or number.
102
- const runMonitor = this . run ( ) ;
103
- this . runPromise = runMonitor ;
92
+ this . _pluginService = pluginService ;
93
+ this . _hostListProvider = hostListProvider ;
94
+ this . _properties = props ;
95
+ this . refreshRateMs = refreshRateMs ;
96
+ this . highRefreshRateMs = highRefreshRateMs ;
97
+ this . runPromise = this . run ( ) ;
98
+ }
99
+
100
+ get hostListProvider ( ) : MonitoringRdsHostListProvider {
101
+ return this . _hostListProvider ;
102
+ }
103
+ get pluginService ( ) : PluginService {
104
+ return this . _pluginService ;
105
+ }
106
+ get properties ( ) : Map < string , any > {
107
+ return this . _properties ;
104
108
}
105
109
106
110
async close ( ) : Promise < void > {
@@ -111,10 +115,6 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
111
115
this . hostMonitors . clear ( ) ;
112
116
}
113
117
114
- setClusterId ( clusterId : string ) : void {
115
- this . clusterId = clusterId ;
116
- }
117
-
118
118
async forceMonitoringRefresh ( shouldVerifyWriter : boolean , timeoutMs : number ) : Promise < HostInfo [ ] > {
119
119
const currentHosts = this . topologyMap . get ( this . clusterId ) ;
120
120
if ( currentHosts ) {
@@ -127,7 +127,7 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
127
127
await this . closeConnection ( client ) ;
128
128
}
129
129
130
- return this . waitTillTopologyGetsUpdated ( timeoutMs ) ;
130
+ return await this . waitTillTopologyGetsUpdated ( timeoutMs ) ;
131
131
}
132
132
133
133
async forceRefresh ( client : any , timeoutMs : number ) : Promise < HostInfo [ ] > {
@@ -180,7 +180,7 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
180
180
}
181
181
182
182
try {
183
- const hosts : HostInfo [ ] = await this . queryForTopology ( client ) ;
183
+ const hosts : HostInfo [ ] = await this . _hostListProvider . sqlQueryForTopology ( client ) ;
184
184
if ( hosts ) {
185
185
this . updateTopologyCache ( hosts ) ;
186
186
}
@@ -191,58 +191,46 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
191
191
return null ;
192
192
}
193
193
194
- private openAnyClientAndUpdateTopology ( ) {
195
- // TODO: implement method.
196
- return [ ] ;
197
- }
198
-
199
- async queryForTopology ( targetClient : ClientWrapper ) : Promise < HostInfo [ ] > {
200
- const dialect = this . hostListProviderService . getDialect ( ) ;
201
- if ( ! this . isTopologyAwareDatabaseDialect ( dialect ) ) {
202
- throw new TypeError ( Messages . get ( "RdsHostListProvider.incorrectDialect" ) ) ;
203
- }
204
- return await dialect . queryForTopology ( targetClient , this . hostListProvider ) . then ( ( res : any ) => this . processQueryResults ( res ) ) ;
205
- }
206
-
207
- protected isTopologyAwareDatabaseDialect ( arg : any ) : arg is TopologyAwareDatabaseDialect {
208
- return arg ;
209
- }
210
-
211
- private async processQueryResults ( result : HostInfo [ ] ) : Promise < HostInfo [ ] > {
212
- const hostMap : Map < string , HostInfo > = new Map < string , HostInfo > ( ) ;
213
-
214
- let hosts : HostInfo [ ] = [ ] ;
215
- const writers : HostInfo [ ] = [ ] ;
216
- result . forEach ( ( host ) => {
217
- hostMap . set ( host . host , host ) ;
218
- } ) ;
194
+ private async openAnyClientAndUpdateTopology ( ) {
195
+ if ( ! this . monitoringClient ) {
196
+ let client ;
197
+ try {
198
+ client = await this . _pluginService . forceConnect ( this . initialHostInfo , this . _properties ) ;
199
+ if ( ! this . monitoringClient ) {
200
+ this . monitoringClient = client ;
201
+ client = await this . _pluginService . forceConnect ( this . initialHostInfo , this . _properties ) ;
202
+ }
203
+ } catch {
204
+ logger . debug ( `Could not connect to: ${ this . initialHostInfo . host } ` ) ;
205
+ return null ;
206
+ }
219
207
220
- hostMap . forEach ( ( host ) => {
221
- if ( host . role !== HostRole . WRITER ) {
222
- hosts . push ( host ) ;
208
+ if ( client && ! this . monitoringClient ) {
209
+ this . monitoringClient = client ;
210
+ logger . debug ( `Opened monitoring connection to: ${ this . initialHostInfo . host } ` ) ;
211
+ if ( this . getWriterHostId ( this . monitoringClient ) !== null ) {
212
+ this . isVerifiedWriterConnection = true ;
213
+ this . writerHostInfo = this . initialHostInfo ;
214
+ }
223
215
} else {
224
- writers . push ( host ) ;
216
+ // Monitoring connection already set by another task, close the new connection.
217
+ this . untrackedPromises . push ( this . closeConnection ( client ) ) ;
225
218
}
226
- } ) ;
219
+ }
227
220
228
- const writerCount : number = writers . length ;
229
- if ( writerCount === 0 ) {
230
- hosts = [ ] ;
231
- } else if ( writerCount === 1 ) {
232
- hosts . push ( writers [ 0 ] ) ;
233
- } else {
234
- const sortedWriters : HostInfo [ ] = writers . sort ( ( a , b ) => {
235
- return b . lastUpdateTime - a . lastUpdateTime ;
236
- } ) ;
221
+ const hosts : HostInfo [ ] = await this . fetchTopologyAndUpdateCache ( this . monitoringClient ) ;
222
+ if ( ! hosts ) {
223
+ const clientToClose = this . monitoringClient ;
224
+ this . monitoringClient = null ;
225
+ this . isVerifiedWriterConnection = false ;
237
226
238
- hosts . push ( sortedWriters [ 0 ] ) ;
227
+ this . untrackedPromises . push ( this . closeConnection ( clientToClose ) ) ;
239
228
}
240
-
241
229
return hosts ;
242
230
}
243
231
244
232
updateTopologyCache ( hosts : HostInfo [ ] ) {
245
- this . topologyMap . put ( this . clusterId , hosts , this . topologyCacheExpirationNanos ) ;
233
+ this . topologyMap . put ( this . clusterId , hosts , ClusterToplogyMonitorImpl . TOPOLOGY_CACHE_EXPIRATION_MS ) ;
246
234
this . releaseTopologyUpdate ( ) ;
247
235
this . topologyUpdated = new Promise < void > ( ( done ) => {
248
236
this . releaseTopologyUpdate = ( ) => {
@@ -252,14 +240,14 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
252
240
}
253
241
254
242
getWriterHostId ( client : ClientWrapper ) {
255
- return client . hostInfo . role === HostRole . WRITER ? client . id : null ;
243
+ return client && client . hostInfo . role === HostRole . WRITER ? client . id : null ;
256
244
}
257
245
258
- async closeConnection ( client : any ) {
246
+ async closeConnection ( client : ClientWrapper ) {
259
247
if ( ! client ) {
260
248
return ;
261
249
}
262
- await this . pluginService . abortTargetClient ( client ) ;
250
+ await this . _pluginService . abortTargetClient ( client ) ;
263
251
}
264
252
265
253
private isInPanicMode ( ) {
@@ -284,7 +272,7 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
284
272
// Use any client to gather topology information.
285
273
let hosts : HostInfo [ ] = this . topologyMap . get ( this . clusterId ) ;
286
274
if ( ! hosts ) {
287
- hosts = this . openAnyClientAndUpdateTopology ( ) ;
275
+ hosts = await this . openAnyClientAndUpdateTopology ( ) ;
288
276
}
289
277
290
278
// Set up host monitors.
@@ -307,15 +295,13 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
307
295
// Writer detected, update monitoringClient.
308
296
const client = this . monitoringClient ;
309
297
this . monitoringClient = writerClient ;
310
- await this . closeConnection ( client ) ;
298
+ this . untrackedPromises . push ( this . closeConnection ( client ) ) ;
311
299
this . isVerifiedWriterConnection = true ;
312
- this . highRefreshRateEndTime = Date . now ( ) + this . highRefreshPeriodAfterPanic ;
313
- this . ignoreNewTopologyRequestsEndTime = Date . now ( ) - this . ignoreTopologyRequest ;
300
+ this . highRefreshRateEndTime = Date . now ( ) + this . highRefreshPeriodAfterPanicMs ;
301
+ this . ignoreNewTopologyRequestsEndTime = Date . now ( ) + this . ignoreTopologyRequestMs ;
314
302
315
303
// Stop monitoring of each host, writer detected.
316
304
this . hostMonitorsStop = true ;
317
- await Promise . all ( this . untrackedPromises ) ;
318
- this . untrackedPromises = [ ] ;
319
305
this . hostMonitors . clear ( ) ;
320
306
continue ;
321
307
} else {
@@ -340,25 +326,23 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
340
326
if ( this . hostMonitors . size !== 0 ) {
341
327
// Stop host monitors.
342
328
this . hostMonitorsStop = true ;
343
- await Promise . all ( this . untrackedPromises ) ;
344
- this . untrackedPromises = [ ] ;
345
329
this . hostMonitors . clear ( ) ;
346
330
}
347
- const hosts = this . fetchTopologyAndUpdateCache ( this . monitoringClient ) ;
331
+ const hosts = await this . fetchTopologyAndUpdateCache ( this . monitoringClient ) ;
348
332
if ( ! hosts ) {
349
333
// Unable to gather topology, switch to panic mode.
350
334
const client = this . monitoringClient ;
351
335
this . monitoringClient = null ;
352
336
this . isVerifiedWriterConnection = false ;
353
- await this . closeConnection ( client ) ;
337
+ this . untrackedPromises . push ( this . closeConnection ( client ) ) ;
354
338
continue ;
355
339
}
356
340
if ( this . highRefreshRateEndTime > 0 && Date . now ( ) > this . highRefreshRateEndTime ) {
357
341
this . highRefreshRateEndTime = 0 ;
358
342
}
359
343
if ( this . highRefreshRateEndTime == 0 ) {
360
344
// Log topology when not in high refresh rate.
361
- logger . debug ( logTopology ( this . topologyMap . get ( this . clusterId ) , "" ) ) ;
345
+ this . logTopology ( "" ) ;
362
346
}
363
347
// Set an easily interruptible delay between topology refreshes.
364
348
await this . delay ( false ) ;
@@ -379,12 +363,19 @@ export class ClusterToplogyMonitorImpl implements ClusterToplogyMonitor {
379
363
}
380
364
381
365
private async delay ( useHighRefreshRate : boolean ) {
382
- const endTime = Date . now ( ) + ( useHighRefreshRate ? this . highRefreshRate : this . refreshRate ) ;
366
+ const endTime = Date . now ( ) + ( useHighRefreshRate ? this . highRefreshRateMs : this . refreshRateMs ) ;
383
367
while ( Date . now ( ) < endTime && ! this . requestToUpdateTopology ) {
384
368
await sleep ( 50 ) ;
385
369
}
386
370
this . requestToUpdateTopology = false ;
387
371
}
372
+
373
+ logTopology ( msgPrefix : string ) {
374
+ const hosts : HostInfo [ ] = this . topologyMap . get ( this . clusterId ) ;
375
+ if ( hosts && hosts . length !== 0 ) {
376
+ logger . debug ( logTopology ( hosts , msgPrefix ) ) ;
377
+ }
378
+ }
388
379
}
389
380
390
381
export class HostMonitor {
@@ -433,9 +424,8 @@ export class HostMonitor {
433
424
this . monitor . hostMonitorsStop = true ;
434
425
435
426
await this . monitor . fetchTopologyAndUpdateCache ( client ) ;
436
- logger . debug ( logTopology ( this . monitor . topologyMap . get ( this . monitor . clusterId ) , "" ) ) ;
427
+ this . monitor . logTopology ( "" ) ;
437
428
}
438
-
439
429
client = null ;
440
430
return ;
441
431
} else if ( ! client ) {
@@ -467,7 +457,7 @@ export class HostMonitor {
467
457
468
458
let hosts : HostInfo [ ] ;
469
459
try {
470
- hosts = await this . monitor . queryForTopology ( client ) ;
460
+ hosts = await this . monitor . hostListProvider . sqlQueryForTopology ( client ) ;
471
461
} catch ( error ) {
472
462
return ;
473
463
}
0 commit comments