This repository has been archived by the owner on Jun 12, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
errgroup.go
105 lines (95 loc) · 2.39 KB
/
errgroup.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Package errgroup provides a Group that is capable of collecting errors
// as it waits for a collection of goroutines to finish.
package errgroup
import (
"bytes"
"sync"
)
// MultiError allows returning a group of errors as one error.
type MultiError []error
// Error returns a concatenated string of all contained errors.
func (m MultiError) Error() string {
l := len(m)
if l == 0 {
panic("MultiError with no errors")
}
if l == 1 {
panic("MultiError with only 1 error")
}
var b bytes.Buffer
b.WriteString("multiple errors: ")
for i, e := range m {
b.WriteString(e.Error())
if i != l-1 {
b.WriteString(" | ")
}
}
return b.String()
}
// NewMultiError returns nil if all input errors passed in are nil. Otherwise,
// it coalesces all input errors into a single error instance. Useful for
// code like this:
//
// func doThisAndThat() error {
// err1 := tryThis()
// err2 := tryThat()
// return errgroup.NewMultiError(err1, err2)
// }
//
func NewMultiError(errs ...error) error {
var multiErr MultiError
for _, err := range errs {
if err != nil {
multiErr = append(multiErr, err)
}
}
if len(multiErr) == 1 {
return multiErr[0]
} else if len(multiErr) > 1 {
return multiErr
}
return nil
}
// Group is similar to a sync.WaitGroup, but allows for collecting errors.
// The collected errors are never reset, so unlike a sync.WaitGroup, this Group
// can only be used _once_. That is, you may only call Wait on it once.
type Group struct {
wg sync.WaitGroup
mu sync.Mutex
errors MultiError
}
// Add adds delta, which may be negative. See sync.WaitGroup.Add documentation
// for details.
func (g *Group) Add(delta int) {
g.wg.Add(delta)
}
// Done decrements the Group counter.
func (g *Group) Done() {
g.wg.Done()
}
// Error adds an error to return in Wait. The error must not be nil.
func (g *Group) Error(e error) {
if e == nil {
panic("error must not be nil")
}
g.mu.Lock()
defer g.mu.Unlock()
g.errors = append(g.errors, e)
}
// Wait blocks until the Group counter is zero. If no errors were recorded, it
// returns nil. If one error was recorded, it returns it as is. If more than
// one error was recorded it returns a MultiError which is a slice of errors.
func (g *Group) Wait() error {
g.wg.Wait()
g.mu.Lock()
defer g.mu.Unlock()
errors := g.errors
l := len(errors)
if l == 0 {
return nil
}
if l == 1 {
return errors[0]
}
return errors
}