A more clear way to go here is to use errgroup (documentation).
Package errgroup provides synchronization, error propagation, and Context cancelation for groups of goroutines working on subtasks of a common task.
You can check it out in this example (playground):
var g errgroup.Group
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
// Launch a goroutine to fetch the URL.
url := url // https://golang.org/doc/faq#closures_and_goroutines
g.Go(func() error {
// Fetch the URL.
resp, err := http.Get(url)
if err == nil {
resp.Body.Close()
}
return err
})
}
// Wait for all HTTP fetches to complete.
if err := g.Wait(); err == nil {
fmt.Println("Successfully fetched all URLs.")
} else {
// After all have run, at least one of them has returned an error!
// But all have to finish their work!
// If you want to stop others goroutines when one fail, go ahead reading!
fmt.Println("Unsuccessfully fetched URLs.")
}
But attention: The first call to return a non-nil error cancels the group phrase in the Go documentation is a little bit misleading.
In fact, errgroup.Group if created with a context (WithContext function), will call the cancel function of the context returned by WithContext when a goroutine in the group will return an error, otherwise nothing will be done (read the source code here!).
So, if you want to close your different goroutines, you must use the context returned my WithContext and manage it by yourself inside them, errgroup will just close that context!
Here you can find an example.
To summarize, errgroup can be used in different ways, as shown by the examples.
"just errors", as the above example:
Wait wait that all goroutines end, and then returns the first non-nil error if any from them, or return nil.
In parallel:
You have to create the group with the WithContext function and use the context to manage the context closing.
I created a playground example here with some sleeps!
You have to manually close each goroutines, but using the context you can end them when one close the context.
Pipelines (see more in the examples).