Collect concurrent errors with Group
Concurrently Collecting Errors with a Group
When you need to run multiple independent operations concurrently and collect any errors they produce, you can use a multierror.Group. This is useful for tasks like parallelizing API calls or processing items from a work queue, where you want all operations to complete regardless of individual failures.
The Group provides two primary methods: Go to start a function in a new goroutine, and Wait to block until all started goroutines have finished.
Waiting for Successful Operations
If you start several functions with group.Go and none of them return an error, group.Wait will return nil. This confirms that all concurrent operations completed successfully. You can use sync/atomic to safely verify that all your goroutines executed.
package main
import (
"sync/atomic"
"github.com/hashicorp/go-multierror"
)
func main() {
var group multierror.Group
var ran atomic.Int32
group.Go(func() error { ran.Add(1); return nil })
group.Go(func() error { ran.Add(1); return nil })
result := group.Wait()
if result != nil || ran.Load() != 2 {
panic("expected both functions and no errors")
}
}
Aggregating Errors from Failed Operations
When functions started with group.Go return non-nil errors, group.Wait collects them. After all goroutines finish, Wait returns a single error value that contains all the errors that occurred. If at least one function returns an error, the result of Wait will be non-nil.
The order in which the functions are executed or the errors are collected is not guaranteed. The primary purpose is to know that all tasks have finished and to receive a collection of any errors that happened along the way.
package main
import (
"errors"
"sync/atomic"
"github.com/hashicorp/go-multierror"
)
func main() {
var group multierror.Group
var ran atomic.Int32
group.Go(func() error { ran.Add(1); return errors.New("alpha") })
group.Go(func() error { ran.Add(1); return errors.New("beta") })
result := group.Wait()
if result == nil || ran.Load() != 2 {
panic("expected both functions and errors")
}
}