diff --git a/clientv3/client.go b/clientv3/client.go index 5eca63ff6..f8e8fd735 100644 --- a/clientv3/client.go +++ b/clientv3/client.go @@ -587,10 +587,13 @@ func isUnavailableErr(ctx context.Context, err error) bool { if err == nil { return false } - ev, _ := status.FromError(err) - // Unavailable codes mean the system will be right back. - // (e.g., can't connect, lost leader) - return ev.Code() == codes.Unavailable + ev, ok := status.FromError(err) + if ok { + // Unavailable codes mean the system will be right back. + // (e.g., can't connect, lost leader) + return ev.Code() == codes.Unavailable + } + return false } func toErr(ctx context.Context, err error) error { @@ -610,9 +613,6 @@ func toErr(ctx context.Context, err error) error { if ctx.Err() != nil { err = ctx.Err() } - case codes.Unavailable: - case codes.FailedPrecondition: - err = grpc.ErrClientConnClosing } } return err @@ -632,16 +632,19 @@ func IsConnCanceled(err error) bool { if err == nil { return false } - // >= gRPC v1.10.x + + // >= gRPC v1.23.x s, ok := status.FromError(err) if ok { // connection is canceled or server has already closed the connection return s.Code() == codes.Canceled || s.Message() == "transport is closing" } + // >= gRPC v1.10.x if err == context.Canceled { return true } + // <= gRPC v1.7.x returns 'errors.New("grpc: the client connection is closing")' return strings.Contains(err.Error(), "grpc: the client connection is closing") } diff --git a/clientv3/doc.go b/clientv3/doc.go index 01a3f5961..913cd2825 100644 --- a/clientv3/doc.go +++ b/clientv3/doc.go @@ -90,7 +90,7 @@ // // with etcd clientv3 <= v3.3 // if err == context.Canceled { // // grpc balancer calls 'Get' with an inflight client.Close -// } else if err == grpc.ErrClientConnClosing { +// } else if err == grpc.ErrClientConnClosing { // <= gRCP v1.7.x // // grpc balancer calls 'Get' after client.Close. // } // // with etcd clientv3 >= v3.4 diff --git a/clientv3/integration/kv_test.go b/clientv3/integration/kv_test.go index b31fd0920..f773cffed 100644 --- a/clientv3/integration/kv_test.go +++ b/clientv3/integration/kv_test.go @@ -463,7 +463,7 @@ func TestKVGetErrConnClosed(t *testing.T) { defer close(donec) _, err := cli.Get(context.TODO(), "foo") if !clientv3.IsConnCanceled(err) { - t.Errorf("expected %v or %v, got %v", context.Canceled, grpc.ErrClientConnClosing, err) + t.Errorf("expected %v, got %v", context.Canceled, err) } }() @@ -490,7 +490,7 @@ func TestKVNewAfterClose(t *testing.T) { go func() { _, err := cli.Get(context.TODO(), "foo") if !clientv3.IsConnCanceled(err) { - t.Errorf("expected %v or %v, got %v", context.Canceled, grpc.ErrClientConnClosing, err) + t.Errorf("expected %v, got %v", context.Canceled, err) } close(donec) }() diff --git a/clientv3/integration/lease_test.go b/clientv3/integration/lease_test.go index 111739d39..84f18d529 100644 --- a/clientv3/integration/lease_test.go +++ b/clientv3/integration/lease_test.go @@ -27,8 +27,6 @@ import ( "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/integration" "go.etcd.io/etcd/pkg/testutil" - - "google.golang.org/grpc" ) func TestLeaseNotFoundError(t *testing.T) { @@ -300,9 +298,8 @@ func TestLeaseGrantErrConnClosed(t *testing.T) { defer close(donec) _, err := cli.Grant(context.TODO(), 5) if !clientv3.IsConnCanceled(err) { - // grpc.ErrClientConnClosing if grpc-go balancer calls 'Get' after client.Close. // context.Canceled if grpc-go balancer calls 'Get' with an inflight client.Close. - t.Errorf("expected %v, %v or server unavailable, got %v", err != context.Canceled, grpc.ErrClientConnClosing, err) + t.Errorf("expected %v, or server unavailable, got %v", context.Canceled, err) } }() @@ -372,7 +369,7 @@ func TestLeaseGrantNewAfterClose(t *testing.T) { go func() { _, err := cli.Grant(context.TODO(), 5) if !clientv3.IsConnCanceled(err) { - t.Errorf("expected %v, %v or server unavailable, got %v", err != context.Canceled, grpc.ErrClientConnClosing, err) + t.Errorf("expected %v or server unavailable, got %v", context.Canceled, err) } close(donec) }() @@ -405,7 +402,7 @@ func TestLeaseRevokeNewAfterClose(t *testing.T) { go func() { _, err := cli.Revoke(context.TODO(), leaseID) if !clientv3.IsConnCanceled(err) { - t.Fatalf("expected %v, %v or server unavailable, got %v", err != context.Canceled, grpc.ErrClientConnClosing, err) + t.Fatalf("expected %v or server unavailable, got %v", context.Canceled, err) } close(donec) }()