We have 2 main/parent goroutines and each have 5 sub/child goroutines. In total we have 10 goroutines. What we are going to do is, if any of these fail, all of them will fail. We will do this by returning an error. The example we are using is like playing a game. We are going to pick two random numbers in each sub/child goroutine. If both of them equal to 0 then we will fail the goroutine. Otherwise all will be running forever.


MAIN/PARENT - SUB/CHILD
1 1, 2, 3, 4, 5
2 1, 2, 3, 4, 5

Example


package main

import (
"context"
"fmt"
"math/rand"
"time"

"golang.org/x/sync/errgroup"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

func random(min, max int) int {
if min == 0 {
max = max + 1
}

return rand.Intn(max) + min
}

func main() {
eg, ctx := errgroup.WithContext(context.Background())

for i := 1; i <= 2; i++ {
i := i

eg.Go(func() error {
return child(ctx, eg, i)
})
}

if err := eg.Wait(); err != nil {
fmt.Println(err)
}
}

func child(ctx context.Context, eg *errgroup.Group, id int) error {
for i := 1; i <= 5; i++ {
i := i

eg.Go(func() error {
for ctx.Err() == nil {
a, b := random(0, 3), random(0, 3)

if a == 0 && b == 0 {
return fmt.Errorf("MIAN:%d - CHILD:%d => (%d-%d)\n", id, i, a, b)
}

// Do the work
fmt.Printf("MIAN:%d - CHILD:%d => (%d-%d)\n", id, i, a, b)
}

return nil
})
}

return nil
}

Tests


MIAN:1 - SUB:1 => (0-3)
MIAN:1 - SUB:1 => (1-0)
MIAN:1 - SUB:2 => (0-2)
MIAN:2 - SUB:1 => (1-2)
MIAN:2 - SUB:2 => (3-2)
MIAN:1 - SUB:1 => (0-0)
MIAN:1 - SUB:1 => (0-2)
MIAN:1 - SUB:4 => (1-3)
MIAN:1 - SUB:1 => (3-3)
MIAN:1 - SUB:1 => (0-0)

MIAN:2 - SUB:2 => (2-2)
MIAN:2 - SUB:1 => (2-3)
MIAN:1 - SUB:2 => (3-3)
MIAN:1 - SUB:3 => (0-0)

MIAN:1 - SUB:1 => (3-2)
MIAN:2 - SUB:1 => (0-0)