Collect concurrent errors with Group
When you need to execute multiple independent tasks concurrently and collect all resulting errors rather than just the first one, the Group struct in go-multierror provides a mechanism to run functions in goroutines and coalesce their returns into a single error value.
Running Concurrent Tasks
You use the Go method to schedule work. The Group manages the execution of these goroutines and collects any errors they return. If all functions return nil, the Wait method returns nil. This allows you to use the result of a Group operation just like a standard error in your control flow.
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")
}
}
Collecting Multiple Errors
When functions passed to Go return non-nil errors, Group collects them into a single result. The Wait method blocks until every scheduled goroutine has finished, ensuring that the returned error contains the results from all failed tasks.
The order in which errors are collected depends on the completion timing of the goroutines and is treated as unspecified. Because Group is designed to aggregate failures, it does not stop execution when an error occurs; every function scheduled via Go will run to completion.
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")
}
}