From ec20a7b8578ce839b41c14298bddef0d7019c844 Mon Sep 17 00:00:00 2001 From: iamqizhao <toqizhao@gmail.com> Date: Thu, 4 Jun 2015 15:45:06 -0700 Subject: [PATCH 1/3] make dialing nonblocking by default. Add a DialOption to force blocking operation. --- clientconn.go | 30 +++++++++++++++++++++++++----- test/end2end_test.go | 6 +++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/clientconn.go b/clientconn.go index 25c9282e..c5045800 100644 --- a/clientconn.go +++ b/clientconn.go @@ -61,6 +61,7 @@ var ( // values passed to Dial. type dialOptions struct { codec Codec + block bool copts transport.ConnectOptions } @@ -74,6 +75,15 @@ func WithCodec(c Codec) DialOption { } } +// WithBlock returns a DialOption which makes caller of Dial blocks until the underlying +// connection is up. Without this, Dial returns immediately and connects the server in +// background. +func WithBlock() DialOption { + return func(o *dialOptions) { + o.block = true + } +} + // WithTransportCredentials returns a DialOption which configures a // connection level security credentials (e.g., TLS/SSL). func WithTransportCredentials(creds credentials.TransportAuthenticator) DialOption { @@ -113,6 +123,7 @@ func Dial(target string, opts ...DialOption) (*ClientConn, error) { } cc := &ClientConn{ target: target, + shutdownChan: make(chan struct{}), } for _, opt := range opts { opt(&cc.dopts) @@ -126,12 +137,21 @@ func Dial(target string, opts ...DialOption) (*ClientConn, error) { // Set the default codec. cc.dopts.codec = protoCodec{} } - if err := cc.resetTransport(false); err != nil { - return nil, err + if cc.dopts.block { + if err := cc.resetTransport(false); err != nil { + return nil, err + } + // Start to monitor the error status of transport. + go cc.transportMonitor() + } else { + go func() { + if err := cc.resetTransport(false); err != nil { + grpclog.Printf("Failed to dial %s: %v; please retry.", target, err) + return + } + go cc.transportMonitor() + }() } - cc.shutdownChan = make(chan struct{}) - // Start to monitor the error status of transport. - go cc.transportMonitor() return cc, nil } diff --git a/test/end2end_test.go b/test/end2end_test.go index 73e6cb65..6f573afe 100644 --- a/test/end2end_test.go +++ b/test/end2end_test.go @@ -205,7 +205,7 @@ func (s *testServer) HalfDuplexCall(stream testpb.TestService_HalfDuplexCallServ const tlsDir = "testdata/" func TestDialTimeout(t *testing.T) { - conn, err := grpc.Dial("Non-Existent.Server:80", grpc.WithTimeout(time.Millisecond)) + conn, err := grpc.Dial("Non-Existent.Server:80", grpc.WithTimeout(time.Millisecond), grpc.WithBlock()) if err == nil { conn.Close() } @@ -219,7 +219,7 @@ func TestTLSDialTimeout(t *testing.T) { if err != nil { t.Fatalf("Failed to create credentials %v", err) } - conn, err := grpc.Dial("Non-Existent.Server:80", grpc.WithTransportCredentials(creds), grpc.WithTimeout(time.Millisecond)) + conn, err := grpc.Dial("Non-Existent.Server:80", grpc.WithTransportCredentials(creds), grpc.WithTimeout(time.Millisecond), grpc.WithBlock()) if err == nil { conn.Close() } @@ -238,7 +238,7 @@ func TestReconnectTimeout(t *testing.T) { t.Fatalf("Failed to parse listener address: %v", err) } addr := "localhost:" + port - conn, err := grpc.Dial(addr, grpc.WithTimeout(5*time.Second)) + conn, err := grpc.Dial(addr, grpc.WithTimeout(5*time.Second), grpc.WithBlock()) if err != nil { t.Fatalf("Failed to dial to the server %q: %v", addr, err) } From e2677ad0f37a8bf12ece6ad1d538312dde46051b Mon Sep 17 00:00:00 2001 From: iamqizhao <toqizhao@gmail.com> Date: Thu, 4 Jun 2015 15:47:02 -0700 Subject: [PATCH 2/3] fix some comments --- clientconn.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clientconn.go b/clientconn.go index c5045800..91468c41 100644 --- a/clientconn.go +++ b/clientconn.go @@ -76,8 +76,8 @@ func WithCodec(c Codec) DialOption { } // WithBlock returns a DialOption which makes caller of Dial blocks until the underlying -// connection is up. Without this, Dial returns immediately and connects the server in -// background. +// connection is up. Without this, Dial returns immediately and connecting the server +// happens in background. func WithBlock() DialOption { return func(o *dialOptions) { o.block = true @@ -122,7 +122,7 @@ func Dial(target string, opts ...DialOption) (*ClientConn, error) { return nil, ErrUnspecTarget } cc := &ClientConn{ - target: target, + target: target, shutdownChan: make(chan struct{}), } for _, opt := range opts { From 57b3fb41f6fbbb99cf5f125f45dfffd907738b3f Mon Sep 17 00:00:00 2001 From: iamqizhao <toqizhao@gmail.com> Date: Thu, 4 Jun 2015 15:52:06 -0700 Subject: [PATCH 3/3] add some more comments --- clientconn.go | 1 + 1 file changed, 1 insertion(+) diff --git a/clientconn.go b/clientconn.go index 91468c41..e7bb9453 100644 --- a/clientconn.go +++ b/clientconn.go @@ -144,6 +144,7 @@ func Dial(target string, opts ...DialOption) (*ClientConn, error) { // Start to monitor the error status of transport. go cc.transportMonitor() } else { + // Start a goroutine connecting to the server asynchronously. go func() { if err := cc.resetTransport(false); err != nil { grpclog.Printf("Failed to dial %s: %v; please retry.", target, err)