diff --git a/client/ws_client.go b/client/ws_client.go index 9ed2be8c5..9933ab073 100644 --- a/client/ws_client.go +++ b/client/ws_client.go @@ -86,7 +86,6 @@ func (wsc *WSClient) dial() error { func (wsc *WSClient) OnStop() { wsc.BaseService.OnStop() wsc.Conn.Close() - wsc.Conn = nil // ResultsCh/ErrorsCh is closed in receiveEventsRoutine. } @@ -112,6 +111,9 @@ func (wsc *WSClient) receiveEventsRoutine() { wsc.ResultsCh <- *response.Result } } + // this must be modified in the same go-routine that reads from the + // connection to avoid race conditions + wsc.Conn = nil // Cleanup close(wsc.ResultsCh) diff --git a/server/handlers.go b/server/handlers.go index 5b6008504..573696fb6 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -347,12 +347,15 @@ func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, evsw func (wsc *wsConnection) OnStart() error { wsc.BaseService.OnStart() + // these must be set before the readRoutine is created, as it may + // call wsc.Stop(), which accesses these timers + wsc.readTimeout = time.NewTimer(time.Second * wsReadTimeoutSeconds) + wsc.pingTicker = time.NewTicker(time.Second * wsPingTickerSeconds) + // Read subscriptions/unsubscriptions to events go wsc.readRoutine() // Custom Ping handler to touch readTimeout - wsc.readTimeout = time.NewTimer(time.Second * wsReadTimeoutSeconds) - wsc.pingTicker = time.NewTicker(time.Second * wsPingTickerSeconds) wsc.baseConn.SetPingHandler(func(m string) error { // NOTE: https://github.com/gorilla/websocket/issues/97 go wsc.baseConn.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*wsWriteTimeoutSeconds))