My favorite Go package: errGroup
errGroup makes it really easy to take a bunch of tasks and run them in parallel, making your program faster. They do this whilst keeping your code readable. Let’s take a look!
Here’s an example of one of my most common use-cases I asked chatGPT to generate. In this example, errGroup are being used to make a GET http call to three endpoints.
package main
import (
"context"
"errors"
"fmt"
"net/http"
"golang.org/x/sync/errgroup"
)
func fetchURL(ctx context.Context, url string) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, errors.New(resp.Status)
}
return resp, nil
}
func main() {
urls := []string{
"http://example1.com",
"http://example2.com",
"http://example3.com",
}
g, ctx := errgroup.WithContext(context.Background())
for _, url := range urls {
currentURL := url
g.Go(func() error {
resp, err := fetchURL(ctx, currentURL)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println(currentURL, "was fetched successfully!")
return nil
})
}
if err := g.Wait(); err != nil {
fmt.Printf("Encountered error: %v\n", err)
return
}
fmt.Println("All URLs fetched successfully!")
}
The biggest downside to errGroups is they only return the first error.
This means if you want to “collect” errors from all of the above http requests, you would need to take a different approach. I talk about another approach here.