grpc: close underlying transport when subConn is closed when in connecting state (#4751)

This commit is contained in:
Easwar Swaminathan 2021-09-10 14:08:26 -07:00 committed by GitHub
parent 4e07a14b4e
commit 7f560ef4c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 18 additions and 6 deletions

View File

@ -1322,17 +1322,19 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne
} }
select { select {
case <-time.After(time.Until(connectDeadline)): case <-connectCtx.Done():
// We didn't get the preface in time. // We didn't get the preface in time.
err := fmt.Errorf("failed to receive server preface within timeout") newTr.Close(transport.ErrConnClosing)
newTr.Close(err) if connectCtx.Err() == context.DeadlineExceeded {
channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v: %v", addr, err) err := errors.New("failed to receive server preface within timeout")
return err channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v: %v", addr, err)
return err
}
return nil
case <-prefaceReceived.Done(): case <-prefaceReceived.Done():
// We got the preface - huzzah! things are good. // We got the preface - huzzah! things are good.
ac.mu.Lock() ac.mu.Lock()
defer ac.mu.Unlock() defer ac.mu.Unlock()
defer prefaceReceived.Fire()
if connClosed.HasFired() { if connClosed.HasFired() {
// onClose called first; go idle but do nothing else. // onClose called first; go idle but do nothing else.
if ac.state != connectivity.Shutdown { if ac.state != connectivity.Shutdown {
@ -1340,6 +1342,16 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne
} }
return nil return nil
} }
if ac.state == connectivity.Shutdown {
// This can happen if the subConn was removed while in `Connecting`
// state. tearDown() would have set the state to `Shutdown`, but
// would not have closed the transport since ac.transport would not
// been set at that point.
// We run this in a goroutine because newTr.Close() calls onClose()
// inline, which requires locking ac.mu.
go newTr.Close(transport.ErrConnClosing)
return nil
}
ac.curAddr = addr ac.curAddr = addr
ac.transport = newTr ac.transport = newTr
hcStarted = true hcStarted = true