Reputation: 353
I am trying to find an efficient way to shutdown all my go routines, once i get my OS interrupt signals. Here i am polling events (say from some queue) and processing it in a goroutine. But when i receive OS interrupt, i want to make sure the jobs that are on fly are completed before they are terminated. I also need some additional thing to do only after all the goroutines are completed. The below code seems to work fine for me, but is there any better/efficient way to do this?
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time" // or "runtime"
)
func something(wg *sync.WaitGroup){
defer wg.Done()
fmt.Println("something is happening here...")
time.Sleep(10 * time.Second)
fmt.Println("job done...")
}
func main() {
c := make(chan os.Signal)
mutex := sync.Mutex{}
stop := make(chan int, 1)
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
wg := sync.WaitGroup{}
count := 0
go func() {
<-c
currentTime := time.Now()
fmt.Println("Interrupt signal got at: ", currentTime.String())
// do not let the code shutdown without running everything we needed to do
mutex.Lock()
stop <- 1
fmt.Println("Done .. try shutting down")
wg.Wait()
// do cleanup
time.Sleep(3*time.Second)
fmt.Println("All cleanup completed .. shut down")
currentTime = time.Now()
fmt.Println("Kill at : ", currentTime.String())
mutex.Unlock()
}()
// This for loop is for reading messages from queue like sqs, and it has to be infinite loop because there might be scenarios where there are no events for period of time.
for {
// read off of queue
select {
case stop <- 1:
fmt.Println("Not stopped yet")
wg.Add(1)
go something(&wg)
<- stop
count ++
default:
// try getting the lock before exiting (so that other cleanups are done)
mutex.Lock()
fmt.Println("Done! All jobs completed: Jobs count",count)
return
}
fmt.Println("Processing job -", count)
time.Sleep(1 * time.Second)
}
}
Upvotes: 0
Views: 2751
Reputation: 51587
I believe your solution is unnecessarily complicated. It might be correct, but this is much simpler:
func goroutine(wg *sync.WaitGroup,stop chan struct{}) {
defer wg.Done()
for {
select {
case <-stop:
return
default:
}
// do stuff
}
}
func main() {
stop:=make(chan struct{})
// Setup signal handlers
go func() {
<-c
// This will send the stop signal to all goroutines
close(stop)
}()
// Start goroutines
...
// wait for them to finish
wg.Wait()
Upvotes: 2