Skip to content

Commit 221d586

Browse files
Fix disconnect errors about closed connection
1 parent e4bdbbe commit 221d586

File tree

1 file changed

+60
-12
lines changed

1 file changed

+60
-12
lines changed

websocket/client.go

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,31 @@ func (c *Client) Connect() error {
102102
return nil
103103
}
104104

105-
// Close closes the WebSocket connection
105+
// Close closes the WebSocket connection gracefully
106106
func (c *Client) Close() error {
107-
close(c.done)
108-
if c.conn != nil {
109-
return c.conn.Close()
107+
// Signal shutdown to all goroutines first
108+
select {
109+
case <-c.done:
110+
// Already closed
111+
return nil
112+
default:
113+
close(c.done)
110114
}
111115

112-
// stop the ping monitor
116+
// Set connection status to false
113117
c.setConnected(false)
114118

119+
// Close the WebSocket connection gracefully
120+
if c.conn != nil {
121+
// Send close message
122+
c.writeMux.Lock()
123+
c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
124+
c.writeMux.Unlock()
125+
126+
// Close the connection
127+
return c.conn.Close()
128+
}
129+
115130
return nil
116131
}
117132

@@ -351,9 +366,16 @@ func (c *Client) pingMonitor() {
351366
err := c.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(c.pingTimeout))
352367
c.writeMux.Unlock()
353368
if err != nil {
354-
logger.Error("Ping failed: %v", err)
355-
c.reconnect()
356-
return
369+
// Check if we're shutting down before logging error and reconnecting
370+
select {
371+
case <-c.done:
372+
// Expected during shutdown
373+
return
374+
default:
375+
logger.Error("Ping failed: %v", err)
376+
c.reconnect()
377+
return
378+
}
357379
}
358380
}
359381
}
@@ -365,7 +387,14 @@ func (c *Client) readPumpWithDisconnectDetection() {
365387
if c.conn != nil {
366388
c.conn.Close()
367389
}
368-
c.reconnect()
390+
// Only attempt reconnect if we're not shutting down
391+
select {
392+
case <-c.done:
393+
// Shutting down, don't reconnect
394+
return
395+
default:
396+
c.reconnect()
397+
}
369398
}()
370399

371400
for {
@@ -376,8 +405,21 @@ func (c *Client) readPumpWithDisconnectDetection() {
376405
var msg WSMessage
377406
err := c.conn.ReadJSON(&msg)
378407
if err != nil {
379-
logger.Error("WebSocket read error: %v", err)
380-
return // triggers reconnect via defer
408+
// Check if we're shutting down before logging error
409+
select {
410+
case <-c.done:
411+
// Expected during shutdown, don't log as error
412+
logger.Debug("WebSocket connection closed during shutdown")
413+
return
414+
default:
415+
// Unexpected error during normal operation
416+
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNormalClosure) {
417+
logger.Error("WebSocket read error: %v", err)
418+
} else {
419+
logger.Debug("WebSocket connection closed: %v", err)
420+
}
421+
return // triggers reconnect via defer
422+
}
381423
}
382424

383425
c.handlersMux.RLock()
@@ -396,7 +438,13 @@ func (c *Client) reconnect() {
396438
c.conn = nil
397439
}
398440

399-
go c.connectWithRetry()
441+
// Only reconnect if we're not shutting down
442+
select {
443+
case <-c.done:
444+
return
445+
default:
446+
go c.connectWithRetry()
447+
}
400448
}
401449

402450
func (c *Client) setConnected(status bool) {

0 commit comments

Comments
 (0)