diff --git a/call_test.go b/call_test.go index 97eb9c002a96..64976d7b24c3 100644 --- a/call_test.go +++ b/call_test.go @@ -276,3 +276,18 @@ func TestInvokeCancel(t *testing.T) { cc.Close() server.stop() } + +// TestInvokeCancelClosedNonFail checks that a canceled non-failfast RPC +// on a closed client will terminate. +func TestInvokeCancelClosedNonFailFast(t *testing.T) { + server, cc := setUp(t, 0, math.MaxUint32) + var reply string + cc.Close() + req := "hello" + ctx, cancel := context.WithCancel(context.Background()) + cancel() + if err := Invoke(ctx, "/foo/bar", &req, &reply, cc, FailFast(false)); err == nil { + t.Fatalf("canceled invoke on closed connection should fail") + } + server.stop() +} diff --git a/clientconn.go b/clientconn.go index f5bdafb90742..27e74e6f22be 100644 --- a/clientconn.go +++ b/clientconn.go @@ -479,6 +479,10 @@ func (cc *ClientConn) getTransport(ctx context.Context, opts BalancerGetOptions) if cc.dopts.balancer == nil { // If balancer is nil, there should be only one addrConn available. cc.mu.RLock() + if cc.conns == nil { + cc.mu.RUnlock() + return nil, nil, toRPCErr(ErrClientConnClosing) + } for _, ac = range cc.conns { // Break after the first iteration to get the first addrConn. ok = true