Fix disconnect errors about closed connection

This commit is contained in:
Owen
2025-07-08 08:48:39 -07:00
parent e4bdbbec7c
commit 221d5862fb

View File

@@ -102,16 +102,31 @@ func (c *Client) Connect() error {
return nil return nil
} }
// Close closes the WebSocket connection // Close closes the WebSocket connection gracefully
func (c *Client) Close() error { func (c *Client) Close() error {
// Signal shutdown to all goroutines first
select {
case <-c.done:
// Already closed
return nil
default:
close(c.done) close(c.done)
if c.conn != nil {
return c.conn.Close()
} }
// stop the ping monitor // Set connection status to false
c.setConnected(false) c.setConnected(false)
// Close the WebSocket connection gracefully
if c.conn != nil {
// Send close message
c.writeMux.Lock()
c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
c.writeMux.Unlock()
// Close the connection
return c.conn.Close()
}
return nil return nil
} }
@@ -351,6 +366,12 @@ func (c *Client) pingMonitor() {
err := c.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(c.pingTimeout)) err := c.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(c.pingTimeout))
c.writeMux.Unlock() c.writeMux.Unlock()
if err != nil { if err != nil {
// Check if we're shutting down before logging error and reconnecting
select {
case <-c.done:
// Expected during shutdown
return
default:
logger.Error("Ping failed: %v", err) logger.Error("Ping failed: %v", err)
c.reconnect() c.reconnect()
return return
@@ -358,6 +379,7 @@ func (c *Client) pingMonitor() {
} }
} }
} }
}
// readPumpWithDisconnectDetection reads messages and triggers reconnect on error // readPumpWithDisconnectDetection reads messages and triggers reconnect on error
func (c *Client) readPumpWithDisconnectDetection() { func (c *Client) readPumpWithDisconnectDetection() {
@@ -365,7 +387,14 @@ func (c *Client) readPumpWithDisconnectDetection() {
if c.conn != nil { if c.conn != nil {
c.conn.Close() c.conn.Close()
} }
// Only attempt reconnect if we're not shutting down
select {
case <-c.done:
// Shutting down, don't reconnect
return
default:
c.reconnect() c.reconnect()
}
}() }()
for { for {
@@ -376,9 +405,22 @@ func (c *Client) readPumpWithDisconnectDetection() {
var msg WSMessage var msg WSMessage
err := c.conn.ReadJSON(&msg) err := c.conn.ReadJSON(&msg)
if err != nil { if err != nil {
// Check if we're shutting down before logging error
select {
case <-c.done:
// Expected during shutdown, don't log as error
logger.Debug("WebSocket connection closed during shutdown")
return
default:
// Unexpected error during normal operation
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNormalClosure) {
logger.Error("WebSocket read error: %v", err) logger.Error("WebSocket read error: %v", err)
} else {
logger.Debug("WebSocket connection closed: %v", err)
}
return // triggers reconnect via defer return // triggers reconnect via defer
} }
}
c.handlersMux.RLock() c.handlersMux.RLock()
if handler, ok := c.handlers[msg.Type]; ok { if handler, ok := c.handlers[msg.Type]; ok {
@@ -396,8 +438,14 @@ func (c *Client) reconnect() {
c.conn = nil c.conn = nil
} }
// Only reconnect if we're not shutting down
select {
case <-c.done:
return
default:
go c.connectWithRetry() go c.connectWithRetry()
} }
}
func (c *Client) setConnected(status bool) { func (c *Client) setConnected(status bool) {
c.reconnectMux.Lock() c.reconnectMux.Lock()