diff --git a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts index a7a28c66..5d7cfa04 100644 --- a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -181,7 +181,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { trace('Target ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; - this.parent.updateState(); + this.parent.maybeUpdateState(); } updateAddressList(addressList: SubchannelAddress[], lbConfig: WeightedTarget, attributes: { [key: string]: unknown; }): void { @@ -238,9 +238,16 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { * List of current target names. */ private targetList: string[] = []; + private updatesPaused = false; constructor(private channelControlHelper: ChannelControlHelper) {} + private maybeUpdateState() { + if (!this.updatesPaused) { + this.updateState() + } + } + private updateState() { const pickerList: WeightedPicker[] = []; let end = 0; @@ -343,6 +350,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { childAddressList.push(childAddress); } + this.updatesPaused = true; this.targetList = Array.from(lbConfig.getTargets().keys()); for (const [targetName, targetConfig] of lbConfig.getTargets()) { let target = this.targets.get(targetName); @@ -364,6 +372,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { target.deactivate(); } } + this.updatesPaused = false; this.updateState(); } diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index 6210ea84..bfc55c80 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -144,7 +144,7 @@ class XdsClusterManager implements LoadBalancer { trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; - this.parent.updateState(); + this.parent.maybeUpdateState(); } updateAddressList(addressList: SubchannelAddress[], lbConfig: ClusterManagerChild, attributes: { [key: string]: unknown; }): void { const childConfig = getFirstUsableConfig(lbConfig.child_policy); @@ -173,8 +173,15 @@ class XdsClusterManager implements LoadBalancer { private children: Map = new Map(); // Shutdown is a placeholder value that will never appear in normal operation. private currentState: ConnectivityState = ConnectivityState.SHUTDOWN; + private updatesPaused = false; constructor(private channelControlHelper: ChannelControlHelper) {} + private maybeUpdateState() { + if (!this.updatesPaused) { + this.updateState(); + } + } + private updateState() { const pickerMap: Map = new Map(); let anyReady = false; @@ -250,6 +257,7 @@ class XdsClusterManager implements LoadBalancer { namesToRemove.push(name); } } + this.updatesPaused = true; for (const name of namesToRemove) { this.children.get(name)!.destroy(); this.children.delete(name); @@ -262,6 +270,7 @@ class XdsClusterManager implements LoadBalancer { this.children.set(name, newChild); } } + this.updatesPaused = false; this.updateState(); } exitIdle(): void {