-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherrgroup.go
85 lines (73 loc) · 1.61 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
package errgroup
import (
"context"
"strings"
"sync"
)
// Error is a custom error type to track multiple errors.
type Error struct {
errs []error
}
// Error returns a string concatenation of multiple errors.
func (e Error) Error() string {
msgs := make([]string, 0, len(e.errs))
for _, err := range e.errs {
if err != nil {
msgs = append(msgs, err.Error())
}
}
return strings.Join(msgs, ";")
}
// Errors returns the error of the Go method as a slice.
func (e Error) Errors() []error {
return e.errs
}
// Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
//
// A zero Group is valid and does not cancel.
type Group struct {
wg sync.WaitGroup
mu sync.Mutex
cancel func()
once sync.Once
errs []error
}
// WithContext returns a new Group and an associated Context derived from ctx.
func WithContext(ctx context.Context) (*Group, context.Context) {
egctx, cancel := context.WithCancel(ctx)
return &Group{
cancel: cancel,
}, egctx
}
// Wait blocks until all function calls from the Go method have returned, then
// returns the Error object if they returns an error.
func (g *Group) Wait() error {
g.wg.Wait()
if len(g.errs) > 0 {
return Error{
errs: g.errs,
}
}
return nil
}
// Go calls the given function in a new goroutine.
func (g *Group) Go(f func() error) {
g.wg.Add(1)
go func() {
defer g.wg.Done()
if err := f(); err != nil {
g.once.Do(func() {
if g.cancel != nil {
g.cancel()
}
})
g.mu.Lock()
if g.errs == nil {
g.errs = make([]error, 0)
}
g.errs = append(g.errs, err)
g.mu.Unlock()
}
}()
}