func (cc *Conn) resetTransport(closeTransport bool) error { var retries int start := time.Now() for { cc.mu.Lock() cc.printf("connecting") if cc.state == Shutdown { // cc.Close() has been invoked. cc.mu.Unlock() return ErrClientConnClosing } cc.state = Connecting cc.stateCV.Broadcast() cc.mu.Unlock() if closeTransport { cc.transport.Close() } // Adjust timeout for the current try. copts := cc.dopts.copts if copts.Timeout < 0 { cc.Close() return ErrClientConnTimeout } if copts.Timeout > 0 { copts.Timeout -= time.Since(start) if copts.Timeout <= 0 { cc.Close() return ErrClientConnTimeout } } sleepTime := backoff(retries) timeout := sleepTime if timeout < minConnectTimeout { timeout = minConnectTimeout } if copts.Timeout == 0 || copts.Timeout > timeout { copts.Timeout = timeout } connectTime := time.Now() addr, err := cc.dopts.picker.PickAddr() var newTransport transport.ClientTransport if err == nil { newTransport, err = transport.NewClientTransport(addr, &copts) } if err != nil { cc.mu.Lock() if cc.state == Shutdown { // cc.Close() has been invoked. cc.mu.Unlock() return ErrClientConnClosing } cc.errorf("transient failure: %v", err) cc.state = TransientFailure cc.stateCV.Broadcast() if cc.ready != nil { close(cc.ready) cc.ready = nil } cc.mu.Unlock() sleepTime -= time.Since(connectTime) if sleepTime < 0 { sleepTime = 0 } // Fail early before falling into sleep. if cc.dopts.copts.Timeout > 0 && cc.dopts.copts.Timeout < sleepTime+time.Since(start) { cc.mu.Lock() cc.errorf("connection timeout") cc.mu.Unlock() cc.Close() return ErrClientConnTimeout } closeTransport = false time.Sleep(sleepTime) retries++ grpclog.Printf("grpc: Conn.resetTransport failed to create client transport: %v; Reconnecting to %q", err, cc.target) continue } cc.mu.Lock() cc.printf("ready") if cc.state == Shutdown { // cc.Close() has been invoked. cc.mu.Unlock() newTransport.Close() return ErrClientConnClosing } cc.state = Ready cc.stateCV.Broadcast() cc.transport = newTransport if cc.ready != nil { close(cc.ready) cc.ready = nil } cc.mu.Unlock() return nil } }