Skip to content

Instantly share code, notes, and snippets.

@mumoshu
Last active January 17, 2021 03:12
Show Gist options
  • Save mumoshu/536216f87d13ad1563a635fa97ffa4ac to your computer and use it in GitHub Desktop.
Save mumoshu/536216f87d13ad1563a635fa97ffa4ac to your computer and use it in GitHub Desktop.
errgroup.Groupの亜種(最初のエラーで他のgoroutineをキャンセルする)
package main
import (
"context"
"errors"
"fmt"
"os"
"sync"
"time"
)
// This is a variant of https://github.com/golang/sync/blob/master/errgroup/errgroup.go which
// cancels all the other goroutines on first error.
func main() {
fmt.Println("Hello, playground")
var errOnce sync.Once
var cause error
var wg sync.WaitGroup
ch1 := make(chan string)
ch2 := make(chan string)
defer close(ch1)
defer close(ch2)
go func() {
ch1 <- "to1: a"
ch2 <- "to2: a"
ch1 <- "to1: b"
ch1 <- "err"
}()
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
wg.Add(1)
go func() {
defer wg.Done()
if err := procCh(ctx, "proc1", ch1); err != nil {
errOnce.Do(func() {
cause = err
cancel()
})
}
}()
wg.Add(1)
go func() {
defer wg.Done()
if err := procCh(ctx, "proc2", ch2); err != nil {
errOnce.Do(func() {
cause = err
cancel()
})
}
}()
wg.Wait()
if cause != nil {
println("main", cause.Error())
os.Exit(1)
}
}
func procCh(ctx context.Context, text string, ch chan string) error {
defer println(text, "stopping")
for {
select {
case <-ctx.Done():
return nil
case t := <-ch:
if t == "err" {
println(text, "failed with", t)
return errors.New(t)
}
println(text, "received", t)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment