func (app *app) connectRoutine() { for { run, err := connectAttempt(app) if nil == err { select { case app.connectChan <- run: case <-app.shutdownStarted: } return } if internal.IsDisconnect(err) || internal.IsLicenseException(err) { select { case app.collectorErrorChan <- err: case <-app.shutdownStarted: } return } app.config.Logger.Warn("application connect failure", map[string]interface{}{ "error": err.Error(), }) time.Sleep(internal.ConnectBackoff) } }
func isFatalHarvestError(e error) bool { return internal.IsDisconnect(e) || internal.IsLicenseException(e) || internal.IsRestartException(e) }
func (app *app) process() { // Both the harvest and the run are non-nil when the app is connected, // and nil otherwise. var h *internal.Harvest var run *internal.AppRun for { select { case <-app.harvestTicker.C: if nil != run { now := time.Now() go app.doHarvest(h, now, run) h = internal.NewHarvest(now) } case d := <-app.dataChan: if nil != run && run.RunID == d.id { d.data.MergeIntoHarvest(h) } case <-app.initiateShutdown: close(app.shutdownStarted) // Remove the run before merging any final data to // ensure a bounded number of receives from dataChan. app.setState(nil, errors.New("application shut down")) app.harvestTicker.Stop() if nil != run { for done := false; !done; { select { case d := <-app.dataChan: if run.RunID == d.id { d.data.MergeIntoHarvest(h) } default: done = true } } app.doHarvest(h, time.Now(), run) } close(app.shutdownComplete) return case err := <-app.collectorErrorChan: run = nil h = nil app.setState(nil, nil) switch { case internal.IsDisconnect(err): app.setState(nil, err) app.config.Logger.Error("application disconnected by New Relic", map[string]interface{}{ "app": app.config.AppName, }) case internal.IsLicenseException(err): app.setState(nil, err) app.config.Logger.Error("invalid license", map[string]interface{}{ "app": app.config.AppName, "license": app.config.License, }) case internal.IsRestartException(err): app.config.Logger.Info("application restarted", map[string]interface{}{ "app": app.config.AppName, }) go app.connectRoutine() } case run = <-app.connectChan: h = internal.NewHarvest(time.Now()) app.setState(run, nil) app.config.Logger.Info("application connected", map[string]interface{}{ "app": app.config.AppName, "run": run.RunID.String(), }) processConnectMessages(run, app.config.Logger) } } }