From d94d19243f6a0b6b764c64645b8b2ba10c67546e Mon Sep 17 00:00:00 2001 From: Menghan Li Date: Mon, 16 Nov 2020 11:57:00 -0800 Subject: [PATCH] grpclb: consider IDLE SubConns as connecting (#4031) Otherwise, when the first response is received from the grpclb server, the parent ClientConn enters TransientFailure, and the first several non-wait-for-ready RPCs will fail. --- balancer/grpclb/grpclb.go | 8 ++++++-- balancer/grpclb/grpclb_test.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/balancer/grpclb/grpclb.go b/balancer/grpclb/grpclb.go index a7424cf8d2d7..a43d8964119f 100644 --- a/balancer/grpclb/grpclb.go +++ b/balancer/grpclb/grpclb.go @@ -288,7 +288,11 @@ func (lb *lbBalancer) regeneratePicker(resetDrop bool) { // // The aggregated state is: // - If at least one SubConn in Ready, the aggregated state is Ready; -// - Else if at least one SubConn in Connecting, the aggregated state is Connecting; +// - Else if at least one SubConn in Connecting or IDLE, the aggregated state is Connecting; +// - It's OK to consider IDLE as Connecting. SubConns never stay in IDLE, +// they start to connect immediately. But there's a race between the overall +// state is reported, and when the new SubConn state arrives. And SubConns +// never go back to IDLE. // - Else the aggregated state is TransientFailure. func (lb *lbBalancer) aggregateSubConnStates() connectivity.State { var numConnecting uint64 @@ -298,7 +302,7 @@ func (lb *lbBalancer) aggregateSubConnStates() connectivity.State { switch state { case connectivity.Ready: return connectivity.Ready - case connectivity.Connecting: + case connectivity.Connecting, connectivity.Idle: numConnecting++ } } diff --git a/balancer/grpclb/grpclb_test.go b/balancer/grpclb/grpclb_test.go index dcc5235703a7..dc94ca877843 100644 --- a/balancer/grpclb/grpclb_test.go +++ b/balancer/grpclb/grpclb_test.go @@ -452,7 +452,7 @@ func (s) TestGRPCLB(t *testing.T) { ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - if _, err := testC.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { + if _, err := testC.EmptyCall(ctx, &testpb.Empty{}); err != nil { t.Fatalf("%v.EmptyCall(_, _) = _, %v, want _, ", testC, err) } }