Illustration by Jesse Lucas

Shutdown All Goroutines

Jesse R. Lucas
Forest Giant
Published in
2 min readApr 28, 2016

--

Today I needed a solution to cleanup and stop all goroutines and wait until they returned. I found various patterns online but nothing seemed to fit. When in times of need, I seek the wisdom of others and reference the official Go docs, blog and Dave Cheney’s blog.

After reading Dave’s excellent post Curious Channels I learned a closed channel never blocks, and a nil channel always blocks. This seemed to be the start of the solution! I created a pattern to block the return from exiting each goroutine. Then when I’m ready to return from them I close() the channel.

// Wait until the shutdownChan is closed
<-shutdownChan
return

This seemed to get me half way, but I also wanted to wait until all goroutines were closed before continuing. The sync package was perfect for this. Creating a WaitGroup (wg) and using the wg.Add(1) function for each goroutine. The key is to use defer wg.Done() so when the channel is closed and the func returns it will decrement the WaitGroup count.

So when I need to close all the goroutines I close(shutdownChan) and wait with wg.Wait().

Here’s the pattern: https://play.golang.org/p/zuwmSA1McA

package mainimport (
“fmt”
“sync”
)
func main() {
wg := new(sync.WaitGroup)
shutdownChan := make(chan int)

// Let’s create 100 goroutines
for i := 0; i < 100; i++ {
fmt.Println(“creating goroutine”)
wg.Add(1)
go func(i int) {
defer wg.Done()

// Your code here
fmt.Println(“Do something here”)

// Wait until the shutdownChan is closed
<-shutdownChan
fmt.Printf(“%d goroutine shutdown \n”, i)
return
}(i)
}
close(shutdownChan)
wg.Wait()
fmt.Println(“All go routines shutdown.”)
}

As an experiment I made a package that does this for you. https://github.com/jesselucas/shutdown

--

--

Jesse R. Lucas
Forest Giant

Illustrations and comics at: http://jesselucas.com/ The rest of the time I'm the Interactive Director @forestgiant.