Skip to content

Commit

Permalink
Ensure all goroutines are finished before reconnect
Browse files Browse the repository at this point in the history
In the case where a server dropped the connection to the client the keepalive
routine continued to run, attempted to send a ping on a net.Conn that had
gone away. This change adds an internalConnLost() function to the Client that
ensures that all the client goroutines have finished before starting the
reconnect

Bug: 463046
  • Loading branch information
Al S-M committed Mar 26, 2015
1 parent b0a1972 commit ccf6fcf
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 14 deletions.
14 changes: 14 additions & 0 deletions client.go
Expand Up @@ -366,6 +366,20 @@ func (c *Client) ForceDisconnect() {
c.disconnect()
}

func (c *Client) internalConnLost(err error) {
close(c.stop)
c.conn.Close()
c.workers.Wait()
if c.IsConnected() {
go c.options.OnConnectionLost(c, err)
if c.options.AutoReconnect {
go c.reconnect()
} else {
c.setConnected(false)
}
}
}

func (c *Client) disconnect() {
close(c.stop)
//Wait for all workers to finish before closing connection
Expand Down
10 changes: 1 addition & 9 deletions net.go
Expand Up @@ -268,15 +268,7 @@ func alllogic(c *Client) {
return
case err := <-c.errors:
ERROR.Println(NET, "logic got error")
c.conn.Close()

// Call onConnectionLost or default error handler
if c.IsConnected() {
go c.options.OnConnectionLost(c, err)
if c.options.AutoReconnect {
go c.reconnect()
}
}
c.internalConnLost(err)
return
}
c.lastContact.update()
Expand Down
9 changes: 4 additions & 5 deletions ping.go
Expand Up @@ -40,13 +40,13 @@ func (l *lastcontact) get() time.Time {
}

func keepalive(c *Client) {
defer c.workers.Done()
DEBUG.Println(PNG, "keepalive starting")

for {
select {
case <-c.stop:
DEBUG.Println(PNG, "keepalive stopped")
c.workers.Done()
return
default:
last := uint(time.Since(c.lastContact.get()).Seconds())
Expand All @@ -61,10 +61,9 @@ func keepalive(c *Client) {
c.pingOutstanding = true
} else {
CRITICAL.Println(PNG, "pingresp not received, disconnecting")
go c.options.OnConnectionLost(c, errors.New("pingresp not received, disconnecting"))
if c.options.AutoReconnect {
go c.reconnect()
}
c.workers.Done()
c.internalConnLost(errors.New("pingresp not received, disconnecting"))
return
}
}
time.Sleep(1 * time.Second)
Expand Down

0 comments on commit ccf6fcf

Please sign in to comment.