Codebase list golang-github-nlopes-slack / 9966997
improve disconnect and retry interactions. RTM unconditionally slept for the entire duration of the backoff, ignoring any disconnect signals sent by the library or calling applications. this leads to unnecessary and excessive delays when invoking Disconnect(). - adds error details to the disconnect events for visibility. James Lawrence authored 4 years ago James committed 4 years ago
2 changed file(s) with 18 addition(s) and 17 deletion(s). Raw diff Collapse all Expand all
3434 // DisconnectedEvent contains information about how we disconnected
3535 type DisconnectedEvent struct {
3636 Intentional bool
37 Cause error
3738 }
3839
3940 // LatencyReport contains information about connection latency
99 "time"
1010
1111 "github.com/gorilla/websocket"
12 "github.com/nlopes/slack/internal/errorsx"
1213 "github.com/nlopes/slack/internal/timex"
1314 )
1415
137138 ErrorObj: err,
138139 }}
139140
140 // check if Disconnect() has been invoked.
141 // get time we should wait before attempting to connect again
142 rtm.Debugf("reconnection %d failed: %s reconnecting in %v\n", boff.attempts, err, backoff)
143
144 // wait for one of the following to occur,
145 // backoff duration has elapsed, killChannel is signalled, or
146 // the rtm finishes disconnecting.
141147 select {
148 case <-time.After(backoff): // retry after the backoff.
142149 case intentional := <-rtm.killChannel:
143150 if intentional {
144 rtm.killConnection(intentional)
151 rtm.killConnection(intentional, ErrRTMDisconnected)
145152 return nil, nil, ErrRTMDisconnected
146153 }
147154 case <-rtm.disconnected:
148155 return nil, nil, ErrRTMDisconnected
149 default:
150 }
151
152 // get time we should wait before attempting to connect again
153 rtm.Debugf("reconnection %d failed: %s reconnecting in %v\n", boff.attempts, err, backoff)
154 time.Sleep(backoff)
156 }
155157 }
156158 }
157159
204206 //
205207 // This should not be called directly! Instead a boolean value (true for
206208 // intentional, false otherwise) should be sent to the killChannel on the RTM.
207 func (rtm *RTM) killConnection(intentional bool) (err error) {
209 func (rtm *RTM) killConnection(intentional bool, cause error) (err error) {
208210 rtm.Debugln("killing connection")
209211
210212 if rtm.conn != nil {
211213 err = rtm.conn.Close()
212214 }
213215
214 rtm.IncomingEvents <- RTMEvent{"disconnected", &DisconnectedEvent{intentional}}
216 rtm.IncomingEvents <- RTMEvent{"disconnected", &DisconnectedEvent{Intentional: intentional, Cause: cause}}
215217
216218 if intentional {
217219 rtm.disconnect()
232234 select {
233235 // catch "stop" signal on channel close
234236 case intentional := <-rtm.killChannel:
235 _ = rtm.killConnection(intentional)
237 _ = rtm.killConnection(intentional, errorsx.String("signaled"))
236238 return
237239 // detect when the connection is dead.
238240 case <-rtm.pingDeadman.C:
239 rtm.Debugln("deadman switch trigger disconnecting")
240 _ = rtm.killConnection(false)
241 _ = rtm.killConnection(false, errorsx.String("deadman switch triggered"))
241242 return
242243 // send pings on ticker interval
243244 case <-ticker.C:
244245 if err := rtm.ping(); err != nil {
245 _ = rtm.killConnection(false)
246 _ = rtm.killConnection(false, err)
246247 return
247248 }
248249 case <-rtm.forcePing:
249250 if err := rtm.ping(); err != nil {
250 _ = rtm.killConnection(false)
251 _ = rtm.killConnection(false, err)
251252 return
252253 }
253254 // listen for messages that need to be sent
257258 case rawEvent := <-rtm.rawEvents:
258259 switch rtm.handleRawEvent(rawEvent) {
259260 case rtmEventTypeGoodbye:
260 _ = rtm.killConnection(false)
261 _ = rtm.killConnection(false, errorsx.String("goodbye detected"))
261262 return
262263 default:
263264 }
309310 Message: msg,
310311 ErrorObj: err,
311312 }}
312 // TODO force ping?
313313 }
314314 }
315315