Error handling
- Go course
- Intermediate
- Lesson 28/80
- 6 min
Add error handling in workers and a WaitGroup.
Error handling and shutdown
When a job fails there are two options: report the error with the result and continue, or stop all jobs at the first error. For the second, golang.org/x/sync/errgroup is ideal:
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(3) // at most 3 concurrent jobs
for _, yol := range dosyalar {
g.Go(func() error { return isle(ctx, yol) })
}
if err := g.Wait(); err != nil {
log.Println("ilk hata:", err)
}The first error cancels ctx; the other jobs check ctx and stop early.
Joining errors
If you want "try every job, show all errors at the end", collect the errors and turn them into one with errors.Join (Go 1.20):
var hatalar []error
for s := range sonuclar {
if s.Hata != nil {
hatalar = append(hatalar, fmt.Errorf("iş %d: %w", s.IsID, s.Hata))
}
}
return errors.Join(hatalar...) // nil if there are noneerrors.Is can still find every error inside the joined error.
Practice Collecting errors
Run three jobs; the job with ID 1 returns errors.New("okunamadı"). Wrap the errors from the results with fmt.Errorf("iş %d: %w", ...), collect them and print the result of errors.Join.
Starter code
package main
import (
"errors"
"fmt"
"sync"
)
func main() {
// buraya yaz
}Sample solution
package main
import (
"errors"
"fmt"
"sync"
)
type Sonuc struct {
IsID int
Hata error
}
func main() {
sonuclar := make(chan Sonuc)
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
var err error
if id == 1 {
err = errors.New("okunamadı")
}
sonuclar <- Sonuc{id, err}
}(i)
}
go func() {
wg.Wait()
close(sonuclar)
}()
var hatalar []error
for s := range sonuclar {
if s.Hata != nil {
hatalar = append(hatalar, fmt.Errorf("iş %d: %w", s.IsID, s.Hata))
}
}
fmt.Println(errors.Join(hatalar...))
}Expected output
iş 1: okunamadı
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does <code>g.Wait()</code> return in an errgroup?
- The first non-nil error Correct answer
- A list of all errors
- The last error
- Always nil
Explanation: errgroup keeps the first error and Wait returns it; if all errors are needed, use the result-channel approach or errors.Join.
2 Join the errors
return errors.____(hatalar...)
return errors.Join(hatalar...)
Explanation: errors.Join merges several errors into one; with an empty list it returns nil.
3 Strategy
| Term | Meaning |
|---|---|
Sonuc.Hata |
Report the error, continue |
errgroup |
Stop at the first error |
errors.Join |
Show all errors |
g.SetLimit(3) |
Concurrency limit |