Skip to content

Commit d58144d

Browse files
committed
Merge remote-tracking branch 'upstream/@grpc/grpc-js@1.12.x' into grpc-js_1.12_upmerge
2 parents 5eded95 + 656ca0c commit d58144d

File tree

3 files changed

+59
-40
lines changed

3 files changed

+59
-40
lines changed

packages/grpc-js-xds/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js-xds",
3-
"version": "1.12.0",
3+
"version": "1.12.2",
44
"description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.",
55
"main": "build/src/index.js",
66
"scripts": {

packages/grpc-js/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.12.5",
3+
"version": "1.12.6",
44
"description": "gRPC Library for Node - pure JS implementation",
55
"homepage": "https://grpc.io/",
66
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

packages/grpc-js/src/internal-channel.ts

+57-38
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,13 @@ class ChannelSubchannelWrapper
125125
) => {
126126
channel.throttleKeepalive(keepaliveTime);
127127
};
128-
childSubchannel.addConnectivityStateListener(this.subchannelStateListener);
129128
}
130129

131130
ref(): void {
131+
if (this.refCount === 0) {
132+
this.child.addConnectivityStateListener(this.subchannelStateListener);
133+
this.channel.addWrappedSubchannel(this);
134+
}
132135
this.child.ref();
133136
this.refCount += 1;
134137
}
@@ -160,6 +163,25 @@ class ShutdownPicker implements Picker {
160163
}
161164

162165
export const SUBCHANNEL_ARGS_EXCLUDE_KEY_PREFIX = 'grpc.internal.no_subchannel';
166+
class ChannelzInfoTracker {
167+
readonly trace = new ChannelzTrace();
168+
readonly callTracker = new ChannelzCallTracker();
169+
readonly childrenTracker = new ChannelzChildrenTracker();
170+
state: ConnectivityState = ConnectivityState.IDLE;
171+
constructor(private target: string) {}
172+
173+
getChannelzInfoCallback(): () => ChannelInfo {
174+
return () => {
175+
return {
176+
target: this.target,
177+
state: this.state,
178+
trace: this.trace,
179+
callTracker: this.callTracker,
180+
children: this.childrenTracker.getChildLists()
181+
};
182+
};
183+
}
184+
}
163185

164186
export class InternalChannel {
165187
private readonly resolvingLoadBalancer: ResolvingLoadBalancer;
@@ -181,9 +203,10 @@ export class InternalChannel {
181203
* event loop open while there are any pending calls for the channel that
182204
* have not yet been assigned to specific subchannels. In other words,
183205
* the invariant is that callRefTimer is reffed if and only if pickQueue
184-
* is non-empty.
206+
* is non-empty. In addition, the timer is null while the state is IDLE or
207+
* SHUTDOWN and there are no pending calls.
185208
*/
186-
private readonly callRefTimer: NodeJS.Timeout;
209+
private callRefTimer: NodeJS.Timeout | null = null;
187210
private configSelector: ConfigSelector | null = null;
188211
/**
189212
* This is the error from the name resolver if it failed most recently. It
@@ -205,11 +228,8 @@ export class InternalChannel {
205228

206229
// Channelz info
207230
private readonly channelzEnabled: boolean = true;
208-
private readonly originalTarget: string;
209231
private readonly channelzRef: ChannelRef;
210-
private readonly channelzTrace: ChannelzTrace;
211-
private readonly callTracker = new ChannelzCallTracker();
212-
private readonly childrenTracker = new ChannelzChildrenTracker();
232+
private readonly channelzInfoTracker: ChannelzInfoTracker;
213233

214234
/**
215235
* Randomly generated ID to be passed to the config selector, for use by
@@ -238,7 +258,7 @@ export class InternalChannel {
238258
throw new TypeError('Channel options must be an object');
239259
}
240260
}
241-
this.originalTarget = target;
261+
this.channelzInfoTracker = new ChannelzInfoTracker(target);
242262
const originalTargetUri = parseUri(target);
243263
if (originalTargetUri === null) {
244264
throw new Error(`Could not parse target name "${target}"`);
@@ -252,21 +272,17 @@ export class InternalChannel {
252272
);
253273
}
254274

255-
this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME);
256-
this.callRefTimer.unref?.();
257-
258275
if (this.options['grpc.enable_channelz'] === 0) {
259276
this.channelzEnabled = false;
260277
}
261278

262-
this.channelzTrace = new ChannelzTrace();
263279
this.channelzRef = registerChannelzChannel(
264280
target,
265-
() => this.getChannelzInfo(),
281+
this.channelzInfoTracker.getChannelzInfoCallback(),
266282
this.channelzEnabled
267283
);
268284
if (this.channelzEnabled) {
269-
this.channelzTrace.addTrace('CT_INFO', 'Channel created');
285+
this.channelzInfoTracker.trace.addTrace('CT_INFO', 'Channel created');
270286
}
271287

272288
if (this.options['grpc.default_authority']) {
@@ -312,7 +328,7 @@ export class InternalChannel {
312328
);
313329
subchannel.throttleKeepalive(this.keepaliveTime);
314330
if (this.channelzEnabled) {
315-
this.channelzTrace.addTrace(
331+
this.channelzInfoTracker.trace.addTrace(
316332
'CT_INFO',
317333
'Created subchannel or used existing subchannel',
318334
subchannel.getChannelzRef()
@@ -322,7 +338,6 @@ export class InternalChannel {
322338
subchannel,
323339
this
324340
);
325-
this.wrappedSubchannels.add(wrappedSubchannel);
326341
return wrappedSubchannel;
327342
},
328343
updateState: (connectivityState: ConnectivityState, picker: Picker) => {
@@ -345,12 +360,12 @@ export class InternalChannel {
345360
},
346361
addChannelzChild: (child: ChannelRef | SubchannelRef) => {
347362
if (this.channelzEnabled) {
348-
this.childrenTracker.refChild(child);
363+
this.channelzInfoTracker.childrenTracker.refChild(child);
349364
}
350365
},
351366
removeChannelzChild: (child: ChannelRef | SubchannelRef) => {
352367
if (this.channelzEnabled) {
353-
this.childrenTracker.unrefChild(child);
368+
this.channelzInfoTracker.childrenTracker.unrefChild(child);
354369
}
355370
},
356371
};
@@ -372,7 +387,7 @@ export class InternalChannel {
372387
RETRY_THROTTLER_MAP.delete(this.getTarget());
373388
}
374389
if (this.channelzEnabled) {
375-
this.channelzTrace.addTrace(
390+
this.channelzInfoTracker.trace.addTrace(
376391
'CT_INFO',
377392
'Address resolution succeeded'
378393
);
@@ -395,7 +410,7 @@ export class InternalChannel {
395410
},
396411
status => {
397412
if (this.channelzEnabled) {
398-
this.channelzTrace.addTrace(
413+
this.channelzInfoTracker.trace.addTrace(
399414
'CT_WARNING',
400415
'Address resolution failed with code ' +
401416
status.code +
@@ -447,16 +462,6 @@ export class InternalChannel {
447462
this.lastActivityTimestamp = new Date();
448463
}
449464

450-
private getChannelzInfo(): ChannelInfo {
451-
return {
452-
target: this.originalTarget,
453-
state: this.connectivityState,
454-
trace: this.channelzTrace,
455-
callTracker: this.callTracker,
456-
children: this.childrenTracker.getChildLists(),
457-
};
458-
}
459-
460465
private trace(text: string, verbosityOverride?: LogVerbosity) {
461466
trace(
462467
verbosityOverride ?? LogVerbosity.DEBUG,
@@ -466,6 +471,9 @@ export class InternalChannel {
466471
}
467472

468473
private callRefTimerRef() {
474+
if (!this.callRefTimer) {
475+
this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME)
476+
}
469477
// If the hasRef function does not exist, always run the code
470478
if (!this.callRefTimer.hasRef?.()) {
471479
this.trace(
@@ -479,15 +487,15 @@ export class InternalChannel {
479487
}
480488

481489
private callRefTimerUnref() {
482-
// If the hasRef function does not exist, always run the code
483-
if (!this.callRefTimer.hasRef || this.callRefTimer.hasRef()) {
490+
// If the timer or the hasRef function does not exist, always run the code
491+
if (!this.callRefTimer?.hasRef || this.callRefTimer.hasRef()) {
484492
this.trace(
485493
'callRefTimer.unref | configSelectionQueue.length=' +
486494
this.configSelectionQueue.length +
487495
' pickQueue.length=' +
488496
this.pickQueue.length
489497
);
490-
this.callRefTimer.unref?.();
498+
this.callRefTimer?.unref?.();
491499
}
492500
}
493501

@@ -516,12 +524,13 @@ export class InternalChannel {
516524
ConnectivityState[newState]
517525
);
518526
if (this.channelzEnabled) {
519-
this.channelzTrace.addTrace(
527+
this.channelzInfoTracker.trace.addTrace(
520528
'CT_INFO',
521529
'Connectivity state change to ' + ConnectivityState[newState]
522530
);
523531
}
524532
this.connectivityState = newState;
533+
this.channelzInfoTracker.state = newState;
525534
const watchersCopy = this.connectivityStateWatchers.slice();
526535
for (const watcherObject of watchersCopy) {
527536
if (newState !== watcherObject.currentState) {
@@ -546,6 +555,10 @@ export class InternalChannel {
546555
}
547556
}
548557

558+
addWrappedSubchannel(wrappedSubchannel: ChannelSubchannelWrapper) {
559+
this.wrappedSubchannels.add(wrappedSubchannel);
560+
}
561+
549562
removeWrappedSubchannel(wrappedSubchannel: ChannelSubchannelWrapper) {
550563
this.wrappedSubchannels.delete(wrappedSubchannel);
551564
}
@@ -598,6 +611,10 @@ export class InternalChannel {
598611
clearTimeout(this.idleTimer);
599612
this.idleTimer = null;
600613
}
614+
if (this.callRefTimer) {
615+
clearInterval(this.callRefTimer);
616+
this.callRefTimer = null;
617+
}
601618
}
602619

603620
private startIdleTimeout(timeoutMs: number) {
@@ -641,17 +658,17 @@ export class InternalChannel {
641658

642659
private onCallStart() {
643660
if (this.channelzEnabled) {
644-
this.callTracker.addCallStarted();
661+
this.channelzInfoTracker.callTracker.addCallStarted();
645662
}
646663
this.callCount += 1;
647664
}
648665

649666
private onCallEnd(status: StatusObject) {
650667
if (this.channelzEnabled) {
651668
if (status.code === Status.OK) {
652-
this.callTracker.addCallSucceeded();
669+
this.channelzInfoTracker.callTracker.addCallSucceeded();
653670
} else {
654-
this.callTracker.addCallFailed();
671+
this.channelzInfoTracker.callTracker.addCallFailed();
655672
}
656673
}
657674
this.callCount -= 1;
@@ -755,7 +772,9 @@ export class InternalChannel {
755772
call.cancelWithStatus(Status.UNAVAILABLE, 'Channel closed before call started');
756773
}
757774
this.pickQueue = [];
758-
clearInterval(this.callRefTimer);
775+
if (this.callRefTimer) {
776+
clearInterval(this.callRefTimer);
777+
}
759778
if (this.idleTimer) {
760779
clearTimeout(this.idleTimer);
761780
}

0 commit comments

Comments
 (0)