예제 #1
0
func (watcher *Watcher) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := watcher.logger.Session("watcher")
	logger.Info("starting")
	defer logger.Info("finished")

	var subscription events.EventSource
	subscriptionChan := make(chan events.EventSource, 1)
	go subscribeToEvents(logger, watcher.bbsClient, subscriptionChan)

	eventChan := make(chan models.Event, 1)
	nextErrCount := 0

	close(ready)
	logger.Info("started")

	for {
		select {
		case subscription = <-subscriptionChan:
			if subscription != nil {
				go nextEvent(logger, subscription, eventChan)
			} else {
				go subscribeToEvents(logger, watcher.bbsClient, subscriptionChan)
			}

		case event := <-eventChan:
			if event != nil {
				watcher.handleEvent(logger, event)
			} else {
				nextErrCount += 1
				if nextErrCount > 2 {
					nextErrCount = 0
					go subscribeToEvents(logger, watcher.bbsClient, subscriptionChan)
					break
				}
			}
			go nextEvent(logger, subscription, eventChan)

		case <-signals:
			logger.Info("stopping")
			err := subscription.Close()
			if err != nil {
				logger.Error("failed-closing-event-source", err)
			}
			return nil
		}
	}
}
예제 #2
0
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
	}
}
예제 #3
0
	"github.com/cloudfoundry-incubator/bbs/events"
	"github.com/cloudfoundry-incubator/bbs/models"
	sonde_events "github.com/cloudfoundry/sonde-go/events"
	"github.com/tedsuo/ifrit/ginkgomon"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Events API", func() {
	var (
		done         chan struct{}
		eventChannel chan models.Event

		eventSource    events.EventSource
		baseLRP        *models.ActualLRP
		desiredLRP     *models.DesiredLRP
		key            models.ActualLRPKey
		instanceKey    models.ActualLRPInstanceKey
		newInstanceKey models.ActualLRPInstanceKey
		netInfo        models.ActualLRPNetInfo
	)

	BeforeEach(func() {
		bbsRunner = testrunner.New(bbsBinPath, bbsArgs)
		bbsProcess = ginkgomon.Invoke(bbsRunner)
	})

	JustBeforeEach(func() {
		var err error
		eventSource, err = client.SubscribeToEvents()
		Expect(err).NotTo(HaveOccurred())
예제 #4
0
파일: hub_test.go 프로젝트: Gerg/bbs
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Hub", func() {
	var (
		hub events.Hub
	)

	BeforeEach(func() {
		hub = events.NewHub()
	})

	Describe("RegisterCallback", func() {
		Context("when registering the callback", func() {
			var eventSource events.EventSource
			var counts chan int

			BeforeEach(func() {
				var err error
				eventSource, err = hub.Subscribe()
				Expect(err).NotTo(HaveOccurred())

				counts = make(chan int, 1)
				cbCounts := counts
				hub.RegisterCallback(func(count int) {
					cbCounts <- count
				})
			})

			It("calls the callback immediately with the current subscriber count", func() {
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++
	}
}
예제 #6
0
)

var _ = Describe("Events API", func() {
	Describe("Actual LRPs", func() {
		const (
			processGuid     = "some-process-guid"
			domain          = "some-domain"
			noExpirationTTL = 0
		)

		var (
			done         chan struct{}
			eventChannel chan models.Event

			eventSource    events.EventSource
			baseLRP        *models.ActualLRP
			key            models.ActualLRPKey
			instanceKey    models.ActualLRPInstanceKey
			newInstanceKey models.ActualLRPInstanceKey
			netInfo        models.ActualLRPNetInfo
		)

		JustBeforeEach(func() {
			var err error
			eventSource, err = client.SubscribeToEvents()
			Expect(err).NotTo(HaveOccurred())

			eventChannel = make(chan models.Event)
			done = make(chan struct{})

			go func() {
예제 #7
0
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
		}
	}
}