Fix a goroutine leak in DialContext (#1424)

A leak happens when DialContext times out before a balancer returns any
addresses or before a successful connection is established.

The loop in ClientConn.lbWatcher breaks and doneChan never gets closed.
This commit is contained in:
Andrew Lytvynov 2017-08-04 13:40:50 -07:00 committed by Menghan Li
parent 39c8c3866d
commit 4e56696c6c
2 changed files with 25 additions and 0 deletions

View File

@ -611,6 +611,15 @@ func (cc *ClientConn) GetState() ConnectivityState {
// connections accordingly. If doneChan is not nil, it is closed after the
// first successfull connection is made.
func (cc *ClientConn) lbWatcher(doneChan chan struct{}) {
defer func() {
// In case channel from cc.dopts.balancer.Notify() gets closed before a
// successful connection gets established, don't forget to notify the
// caller.
if doneChan != nil {
close(doneChan)
}
}()
for addrs := range cc.dopts.balancer.Notify() {
var (
add []Address // Addresses need to setup connections.

View File

@ -374,3 +374,19 @@ func TestClientUpdatesParamsAfterGoAway(t *testing.T) {
t.Fatalf("cc.dopts.copts.Keepalive.Time = %v , want 100ms", v)
}
}
func TestClientLBWatcherWithClosedBalancer(t *testing.T) {
b := newBlockingBalancer()
cc := &ClientConn{dopts: dialOptions{balancer: b}}
doneChan := make(chan struct{})
go cc.lbWatcher(doneChan)
// Balancer closes before any successful connections.
b.Close()
select {
case <-doneChan:
case <-time.After(100 * time.Millisecond):
t.Fatal("lbWatcher with closed balancer didn't close doneChan after 100ms")
}
}