Skip to content

Commit f44b5e5

Browse files
authored
Merge pull request #2854 from murgatroid99/grpc-js_lb_child_helper_channel_args
grpc-js: Pass channel args to LB policies with updates
2 parents f621dc6 + 86e62f2 commit f44b5e5

20 files changed

+212
-161
lines changed

packages/grpc-js-xds/interop/xds-interop-client.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import PickResult = grpc.experimental.PickResult;
4141
import PickResultType = grpc.experimental.PickResultType;
4242
import createChildChannelControlHelper = grpc.experimental.createChildChannelControlHelper;
4343
import parseLoadBalancingConfig = grpc.experimental.parseLoadBalancingConfig;
44+
import { ChannelOptions } from '@grpc/grpc-js';
4445

4546
grpc_xds.register();
4647

@@ -88,7 +89,7 @@ const RPC_BEHAVIOR_CHILD_CONFIG = parseLoadBalancingConfig({round_robin: {}});
8889
class RpcBehaviorLoadBalancer implements LoadBalancer {
8990
private child: ChildLoadBalancerHandler;
9091
private latestConfig: RpcBehaviorLoadBalancingConfig | null = null;
91-
constructor(channelControlHelper: ChannelControlHelper, options: grpc.ChannelOptions) {
92+
constructor(channelControlHelper: ChannelControlHelper) {
9293
const childChannelControlHelper = createChildChannelControlHelper(channelControlHelper, {
9394
updateState: (connectivityState, picker) => {
9495
if (connectivityState === grpc.connectivityState.READY && this.latestConfig) {
@@ -97,14 +98,14 @@ class RpcBehaviorLoadBalancer implements LoadBalancer {
9798
channelControlHelper.updateState(connectivityState, picker);
9899
}
99100
});
100-
this.child = new ChildLoadBalancerHandler(childChannelControlHelper, options);
101+
this.child = new ChildLoadBalancerHandler(childChannelControlHelper);
101102
}
102-
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, attributes: { [key: string]: unknown; }): void {
103+
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, options: ChannelOptions): void {
103104
if (!(lbConfig instanceof RpcBehaviorLoadBalancingConfig)) {
104105
return;
105106
}
106107
this.latestConfig = lbConfig;
107-
this.child.updateAddressList(endpointList, RPC_BEHAVIOR_CHILD_CONFIG, attributes);
108+
this.child.updateAddressList(endpointList, RPC_BEHAVIOR_CHILD_CONFIG, options);
108109
}
109110
exitIdle(): void {
110111
this.child.exitIdle();

packages/grpc-js-xds/src/load-balancer-cds.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { XdsConfig } from './xds-dependency-manager';
3030
import { LocalityEndpoint, PriorityChildRaw } from './load-balancer-priority';
3131
import { Locality__Output } from './generated/envoy/config/core/v3/Locality';
3232
import { AGGREGATE_CLUSTER_BACKWARDS_COMPAT, EXPERIMENTAL_OUTLIER_DETECTION } from './environment';
33+
import { XDS_CONFIG_KEY } from './resolver-xds';
3334

3435
const TRACER_NAME = 'cds_balancer';
3536

@@ -91,6 +92,8 @@ export function localityToName(locality: Locality__Output) {
9192
return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`;
9293
}
9394

95+
export const ROOT_CLUSTER_KEY = 'grpc.internal.root_cluster';
96+
9497
export class CdsLoadBalancer implements LoadBalancer {
9598
private childBalancer: ChildLoadBalancerHandler;
9699

@@ -99,8 +102,8 @@ export class CdsLoadBalancer implements LoadBalancer {
99102
private priorityNames: string[] = [];
100103
private nextPriorityChildNumber = 0;
101104

102-
constructor(private readonly channelControlHelper: ChannelControlHelper, options: ChannelOptions) {
103-
this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper, options);
105+
constructor(private readonly channelControlHelper: ChannelControlHelper) {
106+
this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper);
104107
}
105108

106109
private getNextPriorityName(cluster: string) {
@@ -110,14 +113,14 @@ export class CdsLoadBalancer implements LoadBalancer {
110113
updateAddressList(
111114
endpointList: Endpoint[],
112115
lbConfig: TypedLoadBalancingConfig,
113-
attributes: { [key: string]: unknown }
116+
options: ChannelOptions
114117
): void {
115118
if (!(lbConfig instanceof CdsLoadBalancingConfig)) {
116119
trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2));
117120
return;
118121
}
119122
trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2));
120-
const xdsConfig = attributes.xdsConfig as XdsConfig;
123+
const xdsConfig = options[XDS_CONFIG_KEY] as XdsConfig;
121124
const clusterName = lbConfig.getCluster();
122125
const maybeClusterConfig = xdsConfig.clusters.get(clusterName);
123126
if (!maybeClusterConfig) {
@@ -165,7 +168,7 @@ export class CdsLoadBalancer implements LoadBalancer {
165168
this.channelControlHelper.updateState(connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: status.UNAVAILABLE, details: `LB policy config parsing failed with error ${(e as Error).message}`, metadata: new Metadata()}));
166169
return;
167170
}
168-
this.childBalancer.updateAddressList(endpointList, typedChildConfig, {...attributes, rootCluster: clusterName});
171+
this.childBalancer.updateAddressList(endpointList, typedChildConfig, {...options, [ROOT_CLUSTER_KEY]: clusterName});
169172
} else {
170173
if (!clusterConfig.children.endpoints) {
171174
trace('Received update with no resolved endpoints for cluster ' + clusterName);
@@ -180,8 +183,8 @@ export class CdsLoadBalancer implements LoadBalancer {
180183
if (clusterConfig.cluster.type === 'EDS') {
181184
endpointPickingPolicy = clusterConfig.cluster.lbPolicyConfig;
182185
if (AGGREGATE_CLUSTER_BACKWARDS_COMPAT) {
183-
if (typeof attributes.rootCluster === 'string') {
184-
const maybeRootClusterConfig = xdsConfig.clusters.get(attributes.rootCluster);
186+
if (typeof options[ROOT_CLUSTER_KEY] === 'string') {
187+
const maybeRootClusterConfig = xdsConfig.clusters.get(options[ROOT_CLUSTER_KEY]);
185188
if (maybeRootClusterConfig?.success) {
186189
endpointPickingPolicy = maybeRootClusterConfig.value.cluster.lbPolicyConfig;
187190
}
@@ -279,7 +282,7 @@ export class CdsLoadBalancer implements LoadBalancer {
279282
return;
280283
}
281284
trace(JSON.stringify(typedChildConfig.toJsonObject(), undefined, 2));
282-
this.childBalancer.updateAddressList(childEndpointList, typedChildConfig, attributes);
285+
this.childBalancer.updateAddressList(childEndpointList, typedChildConfig, options);
283286
}
284287
}
285288
exitIdle(): void {

packages/grpc-js-xds/src/load-balancer-priority.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
197197
this.parent.channelControlHelper.requestReresolution();
198198
}
199199
}
200-
}), parent.options);
200+
}));
201201
this.picker = new QueuePicker(this.childBalancer);
202202
this.startFailoverTimer();
203203
}
@@ -307,7 +307,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
307307
* The attributes object from the latest update, saved to be passed along to
308308
* each new child as they are created
309309
*/
310-
private latestAttributes: { [key: string]: unknown } = {};
310+
private latestOptions: ChannelOptions = {};
311311
/**
312312
* The latest load balancing policies and address lists for each child from
313313
* the latest update
@@ -323,7 +323,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
323323

324324
private updatesPaused = false;
325325

326-
constructor(private channelControlHelper: ChannelControlHelper, private options: ChannelOptions) {}
326+
constructor(private channelControlHelper: ChannelControlHelper) {}
327327

328328
private updateState(state: ConnectivityState, picker: Picker) {
329329
trace(
@@ -392,7 +392,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
392392
child.updateAddressList(
393393
childUpdate.subchannelAddress,
394394
childUpdate.lbConfig,
395-
this.latestAttributes
395+
this.latestOptions
396396
);
397397
} else {
398398
/* We're going to try to use this child, so reactivate it if it has been
@@ -431,7 +431,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
431431
updateAddressList(
432432
endpointList: Endpoint[],
433433
lbConfig: TypedLoadBalancingConfig,
434-
attributes: { [key: string]: unknown }
434+
options: ChannelOptions
435435
): void {
436436
if (!(lbConfig instanceof PriorityLoadBalancingConfig)) {
437437
// Reject a config of the wrong type
@@ -467,7 +467,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
467467
}
468468
childAddressList.push(childAddress);
469469
}
470-
this.latestAttributes = attributes;
470+
this.latestOptions = options;
471471
this.latestUpdates.clear();
472472
this.priorities = lbConfig.getPriorities();
473473
this.updatesPaused = true;
@@ -486,7 +486,7 @@ export class PriorityLoadBalancer implements LoadBalancer {
486486
existingChild.updateAddressList(
487487
childAddresses,
488488
childConfig.config,
489-
attributes
489+
options
490490
);
491491
}
492492
}

packages/grpc-js-xds/src/load-balancer-ring-hash.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,7 @@ class RingHashLoadBalancer implements LoadBalancer {
225225
private updatesPaused = false;
226226
private currentState: connectivityState = connectivityState.IDLE;
227227
private ring: RingEntry[] = [];
228-
private ringHashSizeCap = DEFAULT_RING_SIZE_CAP;
229-
constructor(private channelControlHelper: ChannelControlHelper, private options: ChannelOptions) {
228+
constructor(private channelControlHelper: ChannelControlHelper) {
230229
this.childChannelControlHelper = createChildChannelControlHelper(
231230
channelControlHelper,
232231
{
@@ -254,9 +253,6 @@ class RingHashLoadBalancer implements LoadBalancer {
254253
},
255254
}
256255
);
257-
if (options['grpc.lb.ring_hash.ring_size_cap'] !== undefined) {
258-
this.ringHashSizeCap = options['grpc.lb.ring_hash.ring_size_cap'];
259-
}
260256
}
261257

262258
private calculateAndUpdateState() {
@@ -316,7 +312,8 @@ class RingHashLoadBalancer implements LoadBalancer {
316312

317313
private constructRing(
318314
endpointList: Endpoint[],
319-
config: RingHashLoadBalancingConfig
315+
config: RingHashLoadBalancingConfig,
316+
ringHashSizeCap: number
320317
) {
321318
this.ring = [];
322319
const endpointWeights: EndpointWeight[] = [];
@@ -336,8 +333,8 @@ class RingHashLoadBalancer implements LoadBalancer {
336333
minNormalizedWeight
337334
);
338335
}
339-
const minRingSize = Math.min(config.getMinRingSize(), this.ringHashSizeCap);
340-
const maxRingSize = Math.min(config.getMaxRingSize(), this.ringHashSizeCap);
336+
const minRingSize = Math.min(config.getMinRingSize(), ringHashSizeCap);
337+
const maxRingSize = Math.min(config.getMaxRingSize(), ringHashSizeCap);
341338
/* Calculate a scale factor that meets the following conditions:
342339
* 1. The result is between minRingSize and maxRingSize, inclusive
343340
* 2. The smallest normalized weight is scaled to a whole number, if it
@@ -390,7 +387,7 @@ class RingHashLoadBalancer implements LoadBalancer {
390387
updateAddressList(
391388
endpointList: Endpoint[],
392389
lbConfig: TypedLoadBalancingConfig,
393-
attributes: { [key: string]: unknown }
390+
options: ChannelOptions
394391
): void {
395392
if (!(lbConfig instanceof RingHashLoadBalancingConfig)) {
396393
trace('Discarding address update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2));
@@ -403,11 +400,11 @@ class RingHashLoadBalancer implements LoadBalancer {
403400
for (const endpoint of endpointList) {
404401
const leafBalancer = this.leafMap.get(endpoint);
405402
if (leafBalancer) {
406-
leafBalancer.updateEndpoint(endpoint);
403+
leafBalancer.updateEndpoint(endpoint, options);
407404
} else {
408405
this.leafMap.set(
409406
endpoint,
410-
new LeafLoadBalancer(endpoint, this.childChannelControlHelper, this.options)
407+
new LeafLoadBalancer(endpoint, this.childChannelControlHelper, options)
411408
);
412409
}
413410
const weight = this.leafWeightMap.get(endpoint);
@@ -420,8 +417,9 @@ class RingHashLoadBalancer implements LoadBalancer {
420417
for (const leaf of removedLeaves) {
421418
leaf.destroy();
422419
}
420+
const ringHashSizeCap = options['grpc.lb.ring_hash.ring_size_cap'] ?? DEFAULT_RING_SIZE_CAP
423421
loadXxhashApi().then(() => {
424-
this.constructRing(dedupedEndpointList, lbConfig);
422+
this.constructRing(dedupedEndpointList, lbConfig, ringHashSizeCap);
425423
this.updatesPaused = false;
426424
this.calculateAndUpdateState();
427425
});

packages/grpc-js-xds/src/load-balancer-weighted-target.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer {
178178
updateState: (connectivityState: ConnectivityState, picker: Picker) => {
179179
this.updateState(connectivityState, picker);
180180
},
181-
}), parent.options);
181+
}));
182182

183183
this.picker = new QueuePicker(this.childBalancer);
184184
}
@@ -190,9 +190,9 @@ export class WeightedTargetLoadBalancer implements LoadBalancer {
190190
this.parent.maybeUpdateState();
191191
}
192192

193-
updateAddressList(endpointList: Endpoint[], lbConfig: WeightedTarget, attributes: { [key: string]: unknown; }): void {
193+
updateAddressList(endpointList: Endpoint[], lbConfig: WeightedTarget, options: ChannelOptions): void {
194194
this.weight = lbConfig.weight;
195-
this.childBalancer.updateAddressList(endpointList, lbConfig.child_policy, attributes);
195+
this.childBalancer.updateAddressList(endpointList, lbConfig.child_policy, options);
196196
}
197197
exitIdle(): void {
198198
this.childBalancer.exitIdle();
@@ -243,7 +243,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer {
243243
private targetList: string[] = [];
244244
private updatesPaused = false;
245245

246-
constructor(private channelControlHelper: ChannelControlHelper, private options: ChannelOptions) {}
246+
constructor(private channelControlHelper: ChannelControlHelper) {}
247247

248248
private maybeUpdateState() {
249249
if (!this.updatesPaused) {
@@ -319,7 +319,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer {
319319
this.channelControlHelper.updateState(connectivityState, picker);
320320
}
321321

322-
updateAddressList(addressList: Endpoint[], lbConfig: TypedLoadBalancingConfig, attributes: { [key: string]: unknown; }): void {
322+
updateAddressList(addressList: Endpoint[], lbConfig: TypedLoadBalancingConfig, options: ChannelOptions): void {
323323
if (!(lbConfig instanceof WeightedTargetLoadBalancingConfig)) {
324324
// Reject a config of the wrong type
325325
trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2));
@@ -365,7 +365,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer {
365365
}
366366
const targetEndpoints = childEndpointMap.get(targetName) ?? [];
367367
trace('Assigning target ' + targetName + ' address list ' + targetEndpoints.map(endpoint => '(' + endpointToString(endpoint) + ' path=' + endpoint.localityPath + ')'));
368-
target.updateAddressList(targetEndpoints, targetConfig, attributes);
368+
target.updateAddressList(targetEndpoints, targetConfig, options);
369369
}
370370

371371
// Deactivate targets that are not in the new config

packages/grpc-js-xds/src/load-balancer-xds-cluster-impl.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import UnavailablePicker = experimental.UnavailablePicker;
4040
import { Locality__Output } from "./generated/envoy/config/core/v3/Locality";
4141
import { ClusterConfig, XdsConfig } from "./xds-dependency-manager";
4242
import { CdsUpdate } from "./xds-resource-type/cluster-resource-type";
43+
import { XDS_CLIENT_KEY, XDS_CONFIG_KEY } from "./resolver-xds";
4344

4445
const TRACER_NAME = 'xds_cluster_impl';
4546

@@ -211,7 +212,7 @@ class XdsClusterImplBalancer implements LoadBalancer {
211212
private xdsClient: XdsClient | null = null;
212213
private latestClusterConfig: ClusterConfig | null = null;
213214

214-
constructor(private readonly channelControlHelper: ChannelControlHelper, options: ChannelOptions) {
215+
constructor(private readonly channelControlHelper: ChannelControlHelper) {
215216
this.childBalancer = new ChildLoadBalancerHandler(createChildChannelControlHelper(channelControlHelper, {
216217
createSubchannel: (subchannelAddress, subchannelArgs) => {
217218
if (!this.xdsClient || !this.latestConfig || !this.lastestEndpointList || !this.latestClusterConfig) {
@@ -248,15 +249,15 @@ class XdsClusterImplBalancer implements LoadBalancer {
248249
channelControlHelper.updateState(connectivityState, picker);
249250
}
250251
}
251-
}), options);
252+
}));
252253
}
253-
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, attributes: { [key: string]: unknown; }): void {
254+
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, options: ChannelOptions): void {
254255
if (!(lbConfig instanceof XdsClusterImplLoadBalancingConfig)) {
255256
trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2));
256257
return;
257258
}
258259
trace('Received update with config: ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2));
259-
const xdsConfig = attributes.xdsConfig as XdsConfig;
260+
const xdsConfig = options[XDS_CONFIG_KEY] as XdsConfig;
260261
const maybeClusterConfig = xdsConfig.clusters.get(lbConfig.getCluster());
261262
if (!maybeClusterConfig) {
262263
trace('Received update with no config for cluster ' + lbConfig.getCluster());
@@ -281,7 +282,7 @@ class XdsClusterImplBalancer implements LoadBalancer {
281282
this.lastestEndpointList = endpointList;
282283
this.latestConfig = lbConfig;
283284
this.latestClusterConfig = clusterConfig;
284-
this.xdsClient = attributes.xdsClient as XdsClient;
285+
this.xdsClient = options[XDS_CLIENT_KEY] as XdsClient;
285286
if (clusterConfig.cluster.lrsLoadReportingServer) {
286287
this.clusterDropStats = this.xdsClient.addClusterDropStats(
287288
clusterConfig.cluster.lrsLoadReportingServer,
@@ -290,7 +291,7 @@ class XdsClusterImplBalancer implements LoadBalancer {
290291
);
291292
}
292293

293-
this.childBalancer.updateAddressList(endpointList, lbConfig.getChildPolicy(), attributes);
294+
this.childBalancer.updateAddressList(endpointList, lbConfig.getChildPolicy(), options);
294295
}
295296
exitIdle(): void {
296297
this.childBalancer.exitIdle();

packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class XdsClusterManager implements LoadBalancer {
131131
updateState: (connectivityState: ConnectivityState, picker: Picker) => {
132132
this.updateState(connectivityState, picker);
133133
},
134-
}), parent.options);
134+
}));
135135

136136
this.picker = new QueuePicker(this.childBalancer);
137137
}
@@ -142,8 +142,8 @@ class XdsClusterManager implements LoadBalancer {
142142
this.picker = picker;
143143
this.parent.maybeUpdateState();
144144
}
145-
updateAddressList(endpointList: Endpoint[], childConfig: TypedLoadBalancingConfig, attributes: { [key: string]: unknown; }): void {
146-
this.childBalancer.updateAddressList(endpointList, childConfig, attributes);
145+
updateAddressList(endpointList: Endpoint[], childConfig: TypedLoadBalancingConfig, options: ChannelOptions): void {
146+
this.childBalancer.updateAddressList(endpointList, childConfig, options);
147147
}
148148
exitIdle(): void {
149149
this.childBalancer.exitIdle();
@@ -167,7 +167,7 @@ class XdsClusterManager implements LoadBalancer {
167167
// Shutdown is a placeholder value that will never appear in normal operation.
168168
private currentState: ConnectivityState = ConnectivityState.SHUTDOWN;
169169
private updatesPaused = false;
170-
constructor(private channelControlHelper: ChannelControlHelper, private options: ChannelOptions) {}
170+
constructor(private channelControlHelper: ChannelControlHelper) {}
171171

172172
private maybeUpdateState() {
173173
if (!this.updatesPaused) {
@@ -207,7 +207,7 @@ class XdsClusterManager implements LoadBalancer {
207207
this.channelControlHelper.updateState(connectivityState, new XdsClusterManagerPicker(pickerMap));
208208
}
209209

210-
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, attributes: { [key: string]: unknown; }): void {
210+
updateAddressList(endpointList: Endpoint[], lbConfig: TypedLoadBalancingConfig, options: ChannelOptions): void {
211211
if (!(lbConfig instanceof XdsClusterManagerLoadBalancingConfig)) {
212212
// Reject a config of the wrong type
213213
trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2));
@@ -234,7 +234,7 @@ class XdsClusterManager implements LoadBalancer {
234234
child = new this.XdsClusterManagerChildImpl(this, name);
235235
this.children.set(name, child);
236236
}
237-
child.updateAddressList(endpointList, childConfig, attributes);
237+
child.updateAddressList(endpointList, childConfig, options);
238238
}
239239
this.updatesPaused = false;
240240
this.updateState();

0 commit comments

Comments
 (0)