package foobar import ( "context" "errors" ) // Controller is a base pattern controller type Controller struct { ctx context.Context workers sync.WaitGroup stopped chan struct{} } // New returns a initialized & started controller func New(ctx context.Context) (c *Controller, err error) { if ctx == nil { err = errors.New("context can't be nill") return } // Init c = &Controller{ ctx: ctx, stopped: make(chan struct{}), } // Start workers c.workers.Add(1) go func() { c.workerA() c.workers.Done() }() c.workers.Add(1) go func() { c.workerB() c.workers.Done() }() // Create the auto-stopper (must be launch after the worker(s) in case ctx is cancelled while launching workers) go c.autostop() // Return the initialized & started controller return } func (c *Controller) autostop() { // Wait for signal <-c.ctx.Done() // Begin the stopping proceedure c.workers.Wait() // TODO: save some state ? // Close the stopped chan to indicate we are fully stopped close(c.stopped) } // WaitStopped will block until c is fully stopped. // To be stopped, c needs to have its context cancelled. // WaitStopped is safe to be called from multiples goroutines. func (c *Controller) WaitStopped() { <-c.stopped }