I have n number of goroutines waiting on a task channel. These goroutines are responsible for performing these tasks. Currently, I'm using beego as my web golang framework. When do I signal termination to my goroutines in a beego application? How do I deduce when a service termination request is received?
As a first step, let's create a channel and bind it to signal which is in your sphere of interest. Then you need to create context and trigger cancelation function when you will receive this signal.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
ctx, cancel := context.WithCancel(context.Background()) // pass your ctx in all goroutines as first argument,
go func() {
signal := <-c
logger.Info("signal was received", zap.Stringer("signal", signal)
cancel()
}()
Then, you can create WaitGroup
and pass your context as first argument in every goroutine
wg := &sync.WaitGroup{}
hooks.RunStartHooks(ctx, wg)
Inside your worker listen to context cancelation working appropriately with wg as specified in docs
for {
select {
case <-ctx.Done():
wg.Done()
return
}
// other cases
}
And finally,
timeout := cfg.Server.HooksCloseTimeout // this is from your config
if waitTimeout(wg, timeout) {
logger.Info("timed out waiting for wait group")
} else {
logger.Info("server exited properly")
}
where waitTimeout is
// waitTimeout waits for the waitgroup for the specified max timeout.
// Returns true if waiting timed out.
func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
c := make(chan struct{})
go func() {
defer close(c)
wg.Wait()
}()
select {
case <-c:
return false // completed normally
case <-time.After(timeout):
return true // timed out
}
}