func (c *Consumer) listenForMessages(conn *connection, callback func(*events.Envelope)) error { if conn.closed() { return nil } ws := conn.websocket() for { if c.idleTimeout != 0 { ws.SetReadDeadline(time.Now().Add(c.idleTimeout)) } _, data, err := ws.ReadMessage() // If the connection was closed (i.e. if conn.Close() was called), we // will have a non-nil error, but we want to return a nil error. if conn.closed() { return nil } if c.isTimeoutErr(err) { return noaa_errors.NewRetryError(err) } if err != nil { return err } envelope := &events.Envelope{} err = proto.Unmarshal(data, envelope) if err != nil { continue } callback(envelope) } }
func (c *Consumer) retryAction(action func() (err error, done bool), errors chan<- error) { oldConnectCallback := c.onConnectCallback() defer c.SetOnConnectCallback(oldConnectCallback) nextSleep := atomic.LoadInt64(&c.minRetryDelay) c.SetOnConnectCallback(func() { atomic.StoreInt64(&nextSleep, atomic.LoadInt64(&c.minRetryDelay)) if oldConnectCallback != nil { oldConnectCallback() } }) for { err, done := action() if done { return } if _, ok := err.(noaa_errors.NonRetryError); ok { c.debugPrinter.Print("WEBSOCKET ERROR", fmt.Sprintf("%s. Retrying...", err.Error())) errors <- err return } if err != nil { c.debugPrinter.Print("WEBSOCKET ERROR", fmt.Sprintf("%s. Retrying...", err.Error())) err = noaa_errors.NewRetryError(err) } errors <- err ns := atomic.LoadInt64(&nextSleep) time.Sleep(time.Duration(ns)) ns = atomic.AddInt64(&nextSleep, ns) max := atomic.LoadInt64(&c.maxRetryDelay) if ns > max { atomic.StoreInt64(&nextSleep, max) } } }
var wg sync.WaitGroup wg.Add(1) defer wg.Wait() go func() { defer wg.Done() repo.TailLogsFor("app-guid", func() {}, logChan, errChan) }() Eventually(errChan).Should(Receive(&err)) close(done) }) It("does not return a RetryError before RetryTimeout", func(done Done) { defer repo.Close() err := noaaerrors.NewRetryError(errors.New("oops")) fakeNoaaConsumer.TailingLogsStub = func(appGuid string, authToken string) (<-chan *events.LogMessage, <-chan error) { e <- err return c, e } var wg sync.WaitGroup wg.Add(1) defer wg.Wait() go func() { defer wg.Done() repo.TailLogsFor("app-guid", func() {}, logChan, errChan) }() Consistently(errChan).ShouldNot(Receive())