package controller import ( "context" "errors" "fmt" "sync" ) type NotifierService interface { RunFetchEvents(ctx context.Context) error } type Controller struct { notifier NotifierService wg sync.WaitGroup errCh chan error cancel context.CancelFunc } func NewController(notifierService NotifierService) *Controller { return &Controller{ notifier: notifierService, wg: sync.WaitGroup{}, errCh: make(chan error, 1), } } // Run service asynchroniously. func (c *Controller) Run(ctx context.Context) { ctx, cancel := context.WithCancel(ctx) c.cancel = cancel c.wg.Add(1) go func() { defer c.wg.Done() if err := c.notifier.RunFetchEvents(ctx); err != nil && !errors.Is(err, context.Canceled) { select { case c.errCh <- fmt.Errorf("RunFetchEvents: %w", err): default: } } }() } // Gracefully stop service. func (c *Controller) Stop(ctx context.Context) error { if c.cancel != nil { c.cancel() } done := make(chan struct{}) go func() { c.wg.Wait() close(done) }() select { case <-done: case <-ctx.Done(): return ctx.Err() } close(c.errCh) select { case err := <-c.errCh: return err default: return nil } }