8 // A contextGroup is a context-aware variation on sync.WaitGroup. It
9 // provides a child context for the added funcs to use, so they can
10 // exit early if another added func returns an error. Its Wait()
11 // method returns the first error returned by any added func.
15 // err := errors.New("oops")
16 // cg := newContextGroup()
18 // cg.Go(func() error {
19 // someFuncWithContext(cg.Context())
22 // cg.Go(func() error {
23 // return err // this cancels cg.Context()
25 // return cg.Wait() // returns err after both goroutines have ended
26 type contextGroup struct {
28 cancel context.CancelFunc
34 // newContextGroup returns a new contextGroup. The caller must
35 // eventually call the Cancel() method of the returned contextGroup.
36 func newContextGroup(ctx context.Context) *contextGroup {
37 ctx, cancel := context.WithCancel(ctx)
44 // Cancel cancels the context group.
45 func (cg *contextGroup) Cancel() {
49 // Context returns a context.Context which will be canceled when all
50 // funcs have succeeded or one has failed.
51 func (cg *contextGroup) Context() context.Context {
55 // Go calls f in a new goroutine. If f returns an error, the
56 // contextGroup is canceled.
58 // If f notices cg.Context() is done, it should abandon further work
59 // and return. In this case, f's return value will be ignored.
60 func (cg *contextGroup) Go(f func() error) {
72 if err != nil && cg.err == nil {
79 // Wait waits for all added funcs to return, and returns the first
82 // If the parent context is canceled before a func returns an error,
83 // Wait returns the parent context's Err().
85 // Wait returns nil if all funcs return nil before the parent context
87 func (cg *contextGroup) Wait() error {