func nextEvent(logger lager.Logger, es events.EventSource, eventChan chan<- models.Event) { event, err := es.Next() switch err { case nil: eventChan <- event case events.ErrSourceClosed: return default: logger.Error("failed-getting-next-event", err) // wait a bit before retrying time.Sleep(time.Second) eventChan <- nil } }
bbsRunner = testrunner.New(bbsBinPath, bbsArgs) bbsProcess = ginkgomon.Invoke(bbsRunner) }) JustBeforeEach(func() { var err error eventSource, err = client.SubscribeToEvents() Expect(err).NotTo(HaveOccurred()) eventChannel = make(chan models.Event) done = make(chan struct{}) go func() { defer close(done) for { event, err := eventSource.Next() if err != nil { close(eventChannel) return } eventChannel <- event } }() rawMessage := json.RawMessage([]byte(`{"port":8080,"hosts":["primer-route"]}`)) primerLRP := &models.DesiredLRP{ ProcessGuid: "primer-guid", Domain: "primer-domain", RootFs: "primer:rootfs", Routes: &models.Routes{ "router": &rawMessage,
func (h *EventStreamHandler) EventStream(w http.ResponseWriter, req *http.Request) { logger := h.logger.Session("event-stream-handler") closeNotifier := w.(http.CloseNotifier).CloseNotify() sourceChan := make(chan events.EventSource) flusher := w.(http.Flusher) go func() { source, err := h.bbs.SubscribeToEvents() if err != nil { logger.Error("failed-to-subscribe-to-events", err) close(sourceChan) return } sourceChan <- source }() var source events.EventSource select { case source = <-sourceChan: if source == nil { w.WriteHeader(http.StatusInternalServerError) return } case <-closeNotifier: return } defer source.Close() go func() { <-closeNotifier source.Close() }() w.Header().Add("Content-Type", "text/event-stream; charset=utf-8") w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate") w.Header().Add("Connection", "keep-alive") w.WriteHeader(http.StatusOK) flusher.Flush() eventID := 0 for { bbsEvent, err := source.Next() if err != nil { logger.Error("failed-to-get-next-event", err) return } event, err := NewEventFromBBS(bbsEvent) if err != nil { logger.Error("failed-to-marshal-event", err) return } payload, err := json.Marshal(event) if err != nil { logger.Error("failed-to-marshal-event", err) return } err = sse.Event{ ID: strconv.Itoa(eventID), Name: string(event.EventType()), Data: payload, }.Write(w) if err != nil { break } flusher.Flush() eventID++ } }
func (watcher *Watcher) Run(signals <-chan os.Signal, ready chan<- struct{}) error { watcher.logger.Info("starting") close(ready) watcher.logger.Info("started") defer watcher.logger.Info("finished") var cachedEvents map[string]models.Event eventChan := make(chan models.Event) syncEndChan := make(chan syncEndEvent) syncing := false var eventSource atomic.Value var stopEventSource int32 startEventSource := func() { go func() { var err error var es events.EventSource for { if atomic.LoadInt32(&stopEventSource) == 1 { return } es, err = watcher.bbsClient.SubscribeToEvents() if err != nil { watcher.logger.Error("failed-subscribing-to-events", err) continue } eventSource.Store(es) var event models.Event for { event, err = es.Next() if err != nil { watcher.logger.Error("failed-getting-next-event", err) // wait a bit before retrying time.Sleep(time.Second) break } if event != nil { eventChan <- event } } } }() } startedEventSource := false for { select { case <-watcher.syncEvents.Sync: if syncing == false { logger := watcher.logger.Session("sync") logger.Info("starting") syncing = true if !startedEventSource { startedEventSource = true startEventSource() } cachedEvents = make(map[string]models.Event) go watcher.sync(logger, syncEndChan) } case syncEnd := <-syncEndChan: watcher.completeSync(syncEnd, cachedEvents) cachedEvents = nil syncing = false syncEnd.logger.Info("complete") case <-watcher.syncEvents.Emit: logger := watcher.logger.Session("emit") watcher.emit(logger) case event := <-eventChan: if syncing { watcher.logger.Info("caching-event", lager.Data{ "type": event.EventType(), }) cachedEvents[event.Key()] = event } else { watcher.handleEvent(watcher.logger, event) } case <-signals: watcher.logger.Info("stopping") atomic.StoreInt32(&stopEventSource, 1) if es := eventSource.Load(); es != nil { err := es.(events.EventSource).Close() if err != nil { watcher.logger.Error("failed-closing-event-source", err) } } return nil } } }