package main import ( "fmt" "os" "os/signal" "sync" "syscall" "time" ) func main() { // create channel for task taskChannel := make(chan bool, 1) // create wait-group wg := new(sync.WaitGroup) // wait for all tasks to finish defer func(*sync.WaitGroup) { wg.Wait() fmt.Printf("All processes stopped, shutting down.\n") }(wg) // add the task to the wait-group wg.Add(1) // start task loop go infiniteTask(wg, taskChannel, time.Duration(time.Second*5)) // keep program running until a shutdown signal is received forever(taskChannel) } func forever(collector chan<- bool) { // create signal channel s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGTERM, syscall.SIGINT) // wait for signal sig := <-s fmt.Printf("\nstarting shutdown procedure, detected signal: %s\n", sig) // send shutdown to collector collector <- true } func infiniteTask(wg *sync.WaitGroup, shutdown <-chan bool, timeout time.Duration) { // set initial time length t := time.NewTimer(timeout) // stop the time when the process ends defer t.Stop() // start infinite loop for { select { // catch timer signal case <-t.C: // trigger task doTask() // reset timer t.Reset(timeout) // catch shutdown signal case <-shutdown: fmt.Printf("Collector Stopped\n") // clear the task from the wait-group wg.Done() // end the loop return // non-blocking channel receiver to allow for checking of either signal default: // wait 1 second to keep the program from eating un-necessary cycles time.Sleep(time.Second * 1) } } } func doTask() { fmt.Printf("Starting task\n") time.Sleep(time.Second * 30) fmt.Printf("Task finished\n") }