Go does not have a built-in "cancellation propagation tree"; you implement it by passing a context.Context down to child goroutines and using context.WithCancelCause to propagate errors. Use golang.org/x/sync/errgroup to manage the group and automatically cancel all children when the first one fails.
package main
import (
"context"
"fmt"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
ctx, cancel := context.WithCancelCause(context.Background())
g, ctx := errgroup.WithContext(ctx)
// Parent task
g.Go(func() error {
<-ctx.Done()
return ctx.Err()
})
// Child tasks
for i := 0; i < 3; i++ {
g.Go(func() error {
select {
case <-time.After(2 * time.Second):
return fmt.Errorf("task %d failed", i)
case <-ctx.Done():
return ctx.Err()
}
})
}
if err := g.Wait(); err != nil {
fmt.Println("Group failed:", err)
}
}