grpc-js: pick_first: fix happy eyeballs and reresolution in sticky TF mode

This commit is contained in:
Michael Lumish 2023-10-19 13:57:57 -07:00
parent ebc2c3e410
commit 2f5ddc7137
2 changed files with 27 additions and 7 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@grpc/grpc-js", "name": "@grpc/grpc-js",
"version": "1.9.6", "version": "1.9.7",
"description": "gRPC Library for Node - pure JS implementation", "description": "gRPC Library for Node - pure JS implementation",
"homepage": "https://grpc.io/", "homepage": "https://grpc.io/",
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

View File

@ -174,6 +174,12 @@ export class PickFirstLoadBalancer implements LoadBalancer {
*/ */
private stickyTransientFailureMode = false; private stickyTransientFailureMode = false;
/**
* Indicates whether we called channelControlHelper.requestReresolution since
* the last call to updateAddressList
*/
private requestedResolutionSinceLastUpdate = false;
/** /**
* The most recent error reported by any subchannel as it transitioned to * The most recent error reported by any subchannel as it transitioned to
* TRANSIENT_FAILURE. * TRANSIENT_FAILURE.
@ -216,15 +222,28 @@ export class PickFirstLoadBalancer implements LoadBalancer {
} }
} }
private maybeEnterStickyTransientFailureMode() { private requestReresolution() {
if (this.stickyTransientFailureMode) { this.requestedResolutionSinceLastUpdate = true;
return; this.channelControlHelper.requestReresolution();
} }
private maybeEnterStickyTransientFailureMode() {
if (!this.allChildrenHaveReportedTF()) { if (!this.allChildrenHaveReportedTF()) {
return; return;
} }
if (!this.requestedResolutionSinceLastUpdate) {
/* Each time we get an update we reset each subchannel's
* hasReportedTransientFailure flag, so the next time we get to this
* point after that, each subchannel has reported TRANSIENT_FAILURE
* at least once since then. That is the trigger for requesting
* reresolution, whether or not the LB policy is already in sticky TF
* mode. */
this.requestReresolution();
}
if (this.stickyTransientFailureMode) {
return;
}
this.stickyTransientFailureMode = true; this.stickyTransientFailureMode = true;
this.channelControlHelper.requestReresolution();
for (const { subchannel } of this.children) { for (const { subchannel } of this.children) {
subchannel.startConnecting(); subchannel.startConnecting();
} }
@ -256,7 +275,7 @@ export class PickFirstLoadBalancer implements LoadBalancer {
if (newState !== ConnectivityState.READY) { if (newState !== ConnectivityState.READY) {
this.removeCurrentPick(); this.removeCurrentPick();
this.calculateAndReportNewState(); this.calculateAndReportNewState();
this.channelControlHelper.requestReresolution(); this.requestReresolution();
} }
return; return;
} }
@ -283,7 +302,7 @@ export class PickFirstLoadBalancer implements LoadBalancer {
private startNextSubchannelConnecting(startIndex: number) { private startNextSubchannelConnecting(startIndex: number) {
clearTimeout(this.connectionDelayTimeout); clearTimeout(this.connectionDelayTimeout);
if (this.triedAllSubchannels || this.stickyTransientFailureMode) { if (this.triedAllSubchannels) {
return; return;
} }
for (const [index, child] of this.children.entries()) { for (const [index, child] of this.children.entries()) {
@ -382,6 +401,7 @@ export class PickFirstLoadBalancer implements LoadBalancer {
this.currentSubchannelIndex = 0; this.currentSubchannelIndex = 0;
this.children = []; this.children = [];
this.triedAllSubchannels = false; this.triedAllSubchannels = false;
this.requestedResolutionSinceLastUpdate = false;
} }
updateAddressList( updateAddressList(