@@ -125,10 +125,13 @@ class ChannelSubchannelWrapper
125
125
) => {
126
126
channel . throttleKeepalive ( keepaliveTime ) ;
127
127
} ;
128
- childSubchannel . addConnectivityStateListener ( this . subchannelStateListener ) ;
129
128
}
130
129
131
130
ref ( ) : void {
131
+ if ( this . refCount === 0 ) {
132
+ this . child . addConnectivityStateListener ( this . subchannelStateListener ) ;
133
+ this . channel . addWrappedSubchannel ( this ) ;
134
+ }
132
135
this . child . ref ( ) ;
133
136
this . refCount += 1 ;
134
137
}
@@ -159,6 +162,26 @@ class ShutdownPicker implements Picker {
159
162
}
160
163
}
161
164
165
+ class ChannelzInfoTracker {
166
+ readonly trace = new ChannelzTrace ( ) ;
167
+ readonly callTracker = new ChannelzCallTracker ( ) ;
168
+ readonly childrenTracker = new ChannelzChildrenTracker ( ) ;
169
+ state : ConnectivityState = ConnectivityState . IDLE ;
170
+ constructor ( private target : string ) { }
171
+
172
+ getChannelzInfoCallback ( ) : ( ) => ChannelInfo {
173
+ return ( ) => {
174
+ return {
175
+ target : this . target ,
176
+ state : this . state ,
177
+ trace : this . trace ,
178
+ callTracker : this . callTracker ,
179
+ children : this . childrenTracker . getChildLists ( )
180
+ } ;
181
+ } ;
182
+ }
183
+ }
184
+
162
185
export class InternalChannel {
163
186
private readonly resolvingLoadBalancer : ResolvingLoadBalancer ;
164
187
private readonly subchannelPool : SubchannelPool ;
@@ -179,9 +202,10 @@ export class InternalChannel {
179
202
* event loop open while there are any pending calls for the channel that
180
203
* have not yet been assigned to specific subchannels. In other words,
181
204
* the invariant is that callRefTimer is reffed if and only if pickQueue
182
- * is non-empty.
205
+ * is non-empty. In addition, the timer is null while the state is IDLE or
206
+ * SHUTDOWN and there are no pending calls.
183
207
*/
184
- private readonly callRefTimer : NodeJS . Timeout ;
208
+ private callRefTimer : NodeJS . Timeout | null = null ;
185
209
private configSelector : ConfigSelector | null = null ;
186
210
/**
187
211
* This is the error from the name resolver if it failed most recently. It
@@ -203,11 +227,8 @@ export class InternalChannel {
203
227
204
228
// Channelz info
205
229
private readonly channelzEnabled : boolean = true ;
206
- private readonly originalTarget : string ;
207
230
private readonly channelzRef : ChannelRef ;
208
- private readonly channelzTrace : ChannelzTrace ;
209
- private readonly callTracker = new ChannelzCallTracker ( ) ;
210
- private readonly childrenTracker = new ChannelzChildrenTracker ( ) ;
231
+ private readonly channelzInfoTracker : ChannelzInfoTracker ;
211
232
212
233
/**
213
234
* Randomly generated ID to be passed to the config selector, for use by
@@ -236,7 +257,7 @@ export class InternalChannel {
236
257
throw new TypeError ( 'Channel options must be an object' ) ;
237
258
}
238
259
}
239
- this . originalTarget = target ;
260
+ this . channelzInfoTracker = new ChannelzInfoTracker ( target ) ;
240
261
const originalTargetUri = parseUri ( target ) ;
241
262
if ( originalTargetUri === null ) {
242
263
throw new Error ( `Could not parse target name "${ target } "` ) ;
@@ -250,21 +271,17 @@ export class InternalChannel {
250
271
) ;
251
272
}
252
273
253
- this . callRefTimer = setInterval ( ( ) => { } , MAX_TIMEOUT_TIME ) ;
254
- this . callRefTimer . unref ?.( ) ;
255
-
256
274
if ( this . options [ 'grpc.enable_channelz' ] === 0 ) {
257
275
this . channelzEnabled = false ;
258
276
}
259
277
260
- this . channelzTrace = new ChannelzTrace ( ) ;
261
278
this . channelzRef = registerChannelzChannel (
262
279
target ,
263
- ( ) => this . getChannelzInfo ( ) ,
280
+ this . channelzInfoTracker . getChannelzInfoCallback ( ) ,
264
281
this . channelzEnabled
265
282
) ;
266
283
if ( this . channelzEnabled ) {
267
- this . channelzTrace . addTrace ( 'CT_INFO' , 'Channel created' ) ;
284
+ this . channelzInfoTracker . trace . addTrace ( 'CT_INFO' , 'Channel created' ) ;
268
285
}
269
286
270
287
if ( this . options [ 'grpc.default_authority' ] ) {
@@ -305,7 +322,7 @@ export class InternalChannel {
305
322
) ;
306
323
subchannel . throttleKeepalive ( this . keepaliveTime ) ;
307
324
if ( this . channelzEnabled ) {
308
- this . channelzTrace . addTrace (
325
+ this . channelzInfoTracker . trace . addTrace (
309
326
'CT_INFO' ,
310
327
'Created subchannel or used existing subchannel' ,
311
328
subchannel . getChannelzRef ( )
@@ -315,7 +332,6 @@ export class InternalChannel {
315
332
subchannel ,
316
333
this
317
334
) ;
318
- this . wrappedSubchannels . add ( wrappedSubchannel ) ;
319
335
return wrappedSubchannel ;
320
336
} ,
321
337
updateState : ( connectivityState : ConnectivityState , picker : Picker ) => {
@@ -338,12 +354,12 @@ export class InternalChannel {
338
354
} ,
339
355
addChannelzChild : ( child : ChannelRef | SubchannelRef ) => {
340
356
if ( this . channelzEnabled ) {
341
- this . childrenTracker . refChild ( child ) ;
357
+ this . channelzInfoTracker . childrenTracker . refChild ( child ) ;
342
358
}
343
359
} ,
344
360
removeChannelzChild : ( child : ChannelRef | SubchannelRef ) => {
345
361
if ( this . channelzEnabled ) {
346
- this . childrenTracker . unrefChild ( child ) ;
362
+ this . channelzInfoTracker . childrenTracker . unrefChild ( child ) ;
347
363
}
348
364
} ,
349
365
} ;
@@ -366,7 +382,7 @@ export class InternalChannel {
366
382
RETRY_THROTTLER_MAP . delete ( this . getTarget ( ) ) ;
367
383
}
368
384
if ( this . channelzEnabled ) {
369
- this . channelzTrace . addTrace (
385
+ this . channelzInfoTracker . trace . addTrace (
370
386
'CT_INFO' ,
371
387
'Address resolution succeeded'
372
388
) ;
@@ -388,7 +404,7 @@ export class InternalChannel {
388
404
} ,
389
405
status => {
390
406
if ( this . channelzEnabled ) {
391
- this . channelzTrace . addTrace (
407
+ this . channelzInfoTracker . trace . addTrace (
392
408
'CT_WARNING' ,
393
409
'Address resolution failed with code ' +
394
410
status . code +
@@ -440,16 +456,6 @@ export class InternalChannel {
440
456
this . lastActivityTimestamp = new Date ( ) ;
441
457
}
442
458
443
- private getChannelzInfo ( ) : ChannelInfo {
444
- return {
445
- target : this . originalTarget ,
446
- state : this . connectivityState ,
447
- trace : this . channelzTrace ,
448
- callTracker : this . callTracker ,
449
- children : this . childrenTracker . getChildLists ( ) ,
450
- } ;
451
- }
452
-
453
459
private trace ( text : string , verbosityOverride ?: LogVerbosity ) {
454
460
trace (
455
461
verbosityOverride ?? LogVerbosity . DEBUG ,
@@ -459,6 +465,9 @@ export class InternalChannel {
459
465
}
460
466
461
467
private callRefTimerRef ( ) {
468
+ if ( ! this . callRefTimer ) {
469
+ this . callRefTimer = setInterval ( ( ) => { } , MAX_TIMEOUT_TIME )
470
+ }
462
471
// If the hasRef function does not exist, always run the code
463
472
if ( ! this . callRefTimer . hasRef ?.( ) ) {
464
473
this . trace (
@@ -472,15 +481,15 @@ export class InternalChannel {
472
481
}
473
482
474
483
private callRefTimerUnref ( ) {
475
- // If the hasRef function does not exist, always run the code
476
- if ( ! this . callRefTimer . hasRef || this . callRefTimer . hasRef ( ) ) {
484
+ // If the timer or the hasRef function does not exist, always run the code
485
+ if ( ! this . callRefTimer ? .hasRef || this . callRefTimer . hasRef ( ) ) {
477
486
this . trace (
478
487
'callRefTimer.unref | configSelectionQueue.length=' +
479
488
this . configSelectionQueue . length +
480
489
' pickQueue.length=' +
481
490
this . pickQueue . length
482
491
) ;
483
- this . callRefTimer . unref ?.( ) ;
492
+ this . callRefTimer ? .unref ?.( ) ;
484
493
}
485
494
}
486
495
@@ -509,12 +518,13 @@ export class InternalChannel {
509
518
ConnectivityState [ newState ]
510
519
) ;
511
520
if ( this . channelzEnabled ) {
512
- this . channelzTrace . addTrace (
521
+ this . channelzInfoTracker . trace . addTrace (
513
522
'CT_INFO' ,
514
523
'Connectivity state change to ' + ConnectivityState [ newState ]
515
524
) ;
516
525
}
517
526
this . connectivityState = newState ;
527
+ this . channelzInfoTracker . state = newState ;
518
528
const watchersCopy = this . connectivityStateWatchers . slice ( ) ;
519
529
for ( const watcherObject of watchersCopy ) {
520
530
if ( newState !== watcherObject . currentState ) {
@@ -539,6 +549,10 @@ export class InternalChannel {
539
549
}
540
550
}
541
551
552
+ addWrappedSubchannel ( wrappedSubchannel : ChannelSubchannelWrapper ) {
553
+ this . wrappedSubchannels . add ( wrappedSubchannel ) ;
554
+ }
555
+
542
556
removeWrappedSubchannel ( wrappedSubchannel : ChannelSubchannelWrapper ) {
543
557
this . wrappedSubchannels . delete ( wrappedSubchannel ) ;
544
558
}
@@ -591,6 +605,10 @@ export class InternalChannel {
591
605
clearTimeout ( this . idleTimer ) ;
592
606
this . idleTimer = null ;
593
607
}
608
+ if ( this . callRefTimer ) {
609
+ clearInterval ( this . callRefTimer ) ;
610
+ this . callRefTimer = null ;
611
+ }
594
612
}
595
613
596
614
private startIdleTimeout ( timeoutMs : number ) {
@@ -634,17 +652,17 @@ export class InternalChannel {
634
652
635
653
private onCallStart ( ) {
636
654
if ( this . channelzEnabled ) {
637
- this . callTracker . addCallStarted ( ) ;
655
+ this . channelzInfoTracker . callTracker . addCallStarted ( ) ;
638
656
}
639
657
this . callCount += 1 ;
640
658
}
641
659
642
660
private onCallEnd ( status : StatusObject ) {
643
661
if ( this . channelzEnabled ) {
644
662
if ( status . code === Status . OK ) {
645
- this . callTracker . addCallSucceeded ( ) ;
663
+ this . channelzInfoTracker . callTracker . addCallSucceeded ( ) ;
646
664
} else {
647
- this . callTracker . addCallFailed ( ) ;
665
+ this . channelzInfoTracker . callTracker . addCallFailed ( ) ;
648
666
}
649
667
}
650
668
this . callCount -= 1 ;
@@ -776,7 +794,9 @@ export class InternalChannel {
776
794
call . cancelWithStatus ( Status . UNAVAILABLE , 'Channel closed before call started' ) ;
777
795
}
778
796
this . pickQueue = [ ] ;
779
- clearInterval ( this . callRefTimer ) ;
797
+ if ( this . callRefTimer ) {
798
+ clearInterval ( this . callRefTimer ) ;
799
+ }
780
800
if ( this . idleTimer ) {
781
801
clearTimeout ( this . idleTimer ) ;
782
802
}
0 commit comments