diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index efb05eb7..55ad714a 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -185,14 +185,7 @@ export class EdsLoadBalancer implements LoadBalancer { private concurrentRequests: number = 0; constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelArgs) => - this.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ), - requestReresolution: () => - this.channelControlHelper.requestReresolution(), + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.channelControlHelper, { updateState: (connectivityState, originalPicker) => { if (this.latestEdsUpdate === null) { return; @@ -243,7 +236,7 @@ export class EdsLoadBalancer implements LoadBalancer { }; this.channelControlHelper.updateState(connectivityState, edsPicker); }, - }); + })); this.watcher = { onValidUpdate: (update) => { trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update, undefined, 2)); diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 566aa04c..145501fe 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -174,20 +174,14 @@ export class LrsLoadBalancer implements LoadBalancer { private localityStatsReporter: XdsClusterLocalityStats | null = null; constructor(private channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelArgs) => - channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ), - requestReresolution: () => channelControlHelper.requestReresolution(), + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(channelControlHelper, { updateState: (connectivityState: ConnectivityState, picker: Picker) => { if (this.localityStatsReporter !== null) { picker = new LoadReportingPicker(picker, this.localityStatsReporter); } channelControlHelper.updateState(connectivityState, picker); }, - }); + })); } updateAddressList( diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index 872ed7d1..b05e459a 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -139,23 +139,11 @@ export class PriorityLoadBalancer implements LoadBalancer { private failoverTimer: NodeJS.Timer | null = null; private deactivationTimer: NodeJS.Timer | null = null; constructor(private parent: PriorityLoadBalancer, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - return this.parent.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ); - }, + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - }, - }); + })); this.picker = new QueuePicker(this.childBalancer); } 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 44a6acf1..a7a28c66 100644 --- a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -168,17 +168,11 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { private weight: number = 0; constructor(private parent: WeightedTargetLoadBalancer, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelOptions) => { - return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); - }, - updateState: (connectivityState, picker) => { + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { + updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - } - }); + })); this.picker = new QueuePicker(this.childBalancer); } 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 7df79e26..6210ea84 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 @@ -131,17 +131,11 @@ class XdsClusterManager implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; constructor(private parent: XdsClusterManager, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelOptions) => { - return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); - }, - updateState: (connectivityState, picker) => { + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { + updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - } - }); + })); this.picker = new QueuePicker(this.childBalancer); } diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 4d158a53..5353f7f5 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -12,6 +12,7 @@ export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, + createChildChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig, diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 870fdb30..19b79764 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -52,6 +52,24 @@ export interface ChannelControlHelper { removeChannelzChild(child: ChannelRef | SubchannelRef): void; } +/** + * Create a child ChannelControlHelper that overrides some methods of the + * parent while letting others pass through to the parent unmodified. This + * allows other code to create these children without needing to know about + * all of the methods to be passed through. + * @param parent + * @param overrides + */ +export function createChildChannelControlHelper(parent: ChannelControlHelper, overrides: Partial): ChannelControlHelper { + return { + createSubchannel: overrides.createSubchannel?.bind(overrides) ?? parent.createSubchannel.bind(parent), + updateState: overrides.updateState?.bind(overrides) ?? parent.updateState.bind(parent), + requestReresolution: overrides.requestReresolution?.bind(overrides) ?? parent.requestReresolution.bind(parent), + addChannelzChild: overrides.addChannelzChild?.bind(overrides) ?? parent.addChannelzChild.bind(parent), + removeChannelzChild: overrides.removeChannelzChild?.bind(overrides) ?? parent.removeChannelzChild.bind(parent) + }; +} + /** * Tracks one or more connected subchannels and determines which subchannel * each request should use. diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index a6e1cc7e..6aa539bf 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit a6e1cc7e328c45a0cb9856c530c8f6cd23314163 +Subproject commit 6aa539bf0195f188ff86efe6fb8bfa2b676cdd46