GODT-2014: bridge quit if gRPC client ends stream (v3)

This commit is contained in:
James Houlahan
2022-11-04 01:18:41 +01:00
parent 8b5cb7729c
commit 8bb60afabd
3 changed files with 50 additions and 15 deletions

View File

@ -55,12 +55,13 @@ const (
type Service struct { // nolint:structcheck
UnimplementedBridgeServer
grpcServer *grpc.Server // the gGRPC server
listener net.Listener
eventStreamCh chan *StreamEvent
eventStreamDoneCh chan struct{}
eventQueue []*StreamEvent
eventQueueMutex sync.Mutex
grpcServer *grpc.Server // the gGRPC server
listener net.Listener
eventStreamCh chan *StreamEvent
eventStreamChMutex sync.RWMutex
eventStreamDoneCh chan struct{}
eventQueue []*StreamEvent
eventQueueMutex sync.Mutex
panicHandler *crash.Handler
restarter *restarter.Restarter

View File

@ -96,12 +96,15 @@ func (s *Service) GuiReady(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empt
// Quit implement the Quit gRPC service call.
func (s *Service) Quit(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Debug("Quit")
return &emptypb.Empty{}, s.quit()
}
func (s *Service) quit() error {
// Windows is notably slow at Quitting. We do it in a goroutine to speed things up a bit.
go func() {
var err error
if s.eventStreamCh != nil {
if _, err = s.StopEventStream(ctx, empty); err != nil {
if s.isStreamingEvents() {
if err = s.stopEventStream(); err != nil {
s.log.WithError(err).Error("Quit failed.")
}
}
@ -110,7 +113,7 @@ func (s *Service) Quit(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empt
s.grpcServer.GracefulStop()
}()
return &emptypb.Empty{}, nil
return nil
}
// Restart implement the Restart gRPC service call.

View File

@ -29,19 +29,19 @@ import (
func (s *Service) RunEventStream(request *EventStreamRequest, server Bridge_RunEventStreamServer) error {
s.log.Debug("Starting Event stream")
if s.eventStreamCh != nil {
if s.isStreamingEvents() {
return status.Errorf(codes.AlreadyExists, "the service is already streaming") // TO-DO GODT-1667 decide if we want to kill the existing stream.
}
s.bridge.SetCurrentPlatform(request.ClientPlatform)
s.eventStreamCh = make(chan *StreamEvent)
s.createEventStreamChannel()
s.eventStreamDoneCh = make(chan struct{})
// TO-DO GODT-1667 We should have a safer we to close this channel? What if an event occur while we are closing?
defer func() {
close(s.eventStreamCh)
s.eventStreamCh = nil
s.deleteEventStreamChannel()
close(s.eventStreamDoneCh)
s.eventStreamDoneCh = nil
}()
@ -70,24 +70,34 @@ func (s *Service) RunEventStream(request *EventStreamRequest, server Bridge_RunE
s.log.Debug("Stop Event stream")
return err
}
case <-server.Context().Done():
s.log.Debug("Client closed the stream, exiting")
return s.quit()
}
}
}
// StopEventStream stops the event stream.
func (s *Service) StopEventStream(_ context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
return &emptypb.Empty{}, s.stopEventStream()
}
func (s *Service) stopEventStream() error {
s.eventStreamChMutex.RLock()
defer s.eventStreamChMutex.RUnlock()
if s.eventStreamCh == nil {
return nil, status.Errorf(codes.NotFound, "The service is not streaming")
return status.Errorf(codes.NotFound, "The service is not streaming")
}
s.eventStreamDoneCh <- struct{}{}
return &emptypb.Empty{}, nil
return nil
}
// SendEvent sends an event to the via the gRPC event stream.
func (s *Service) SendEvent(event *StreamEvent) error {
if s.eventStreamCh == nil { // nobody is connected to the event stream, we queue events
if !s.isStreamingEvents() { // nobody is connected to the event stream, we queue events
s.queueEvent(event)
return nil
}
@ -173,3 +183,24 @@ func (s *Service) queueEvent(event *StreamEvent) {
s.eventQueue = append(s.eventQueue, event)
}
}
func (s *Service) isStreamingEvents() bool {
s.eventStreamChMutex.RLock()
defer s.eventStreamChMutex.RUnlock()
return s.eventStreamCh != nil
}
func (s *Service) createEventStreamChannel() {
s.eventStreamChMutex.Lock()
defer s.eventStreamChMutex.Unlock()
s.eventStreamCh = make(chan *StreamEvent)
}
func (s *Service) deleteEventStreamChannel() {
s.eventStreamChMutex.Lock()
defer s.eventStreamChMutex.Unlock()
s.eventStreamCh = nil
}