Created
January 17, 2022 15:17
-
-
Save sebnyberg/09c2865b3e1636b65d5d918c88ec1f0d to your computer and use it in GitHub Desktop.
concurrent_errors.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"math/rand" | |
"strings" | |
"sync" | |
"time" | |
"golang.org/x/sync/errgroup" | |
) | |
type ManyErrors struct { | |
errors []error | |
mtx sync.Mutex | |
} | |
func (e *ManyErrors) Error() string { | |
errStrs := make([]string, len(e.errors)) | |
for i := range e.errors { | |
errStrs[i] = e.errors[i].Error() | |
} | |
return strings.Join(errStrs, ", ") | |
} | |
func (e *ManyErrors) AddError(err error) { | |
if err != nil { | |
e.mtx.Lock() | |
e.errors = append(e.errors, err) | |
defer e.mtx.Unlock() | |
} | |
} | |
func main() { | |
ctx, cancel := context.WithCancel(context.Background()) | |
defer cancel() | |
// var wg sync.WaitGroup | |
g, gctx := errgroup.WithContext(ctx) | |
var errors ManyErrors | |
poolc := make(chan struct{}, 10) | |
for i := 0; i < 30; i++ { | |
select { | |
case poolc <- struct{}{}: | |
case <-gctx.Done(): | |
fmt.Println("context canceled, stopping work loop") | |
goto breakLoop | |
} | |
x := i | |
g.Go(func() error { | |
defer func() { | |
<-poolc | |
}() | |
if err := maybeFailAfterSomeTime(ctx, x); err != nil { | |
errors.AddError(err) | |
return err | |
} | |
return nil | |
}) | |
} | |
breakLoop: | |
if err := g.Wait(); err != nil { | |
fmt.Println(errors.Error()) | |
} | |
} | |
func maybeFailAfterSomeTime(ctx context.Context, i int) error { | |
fmt.Printf("work %v started...\n", i) | |
ms := time.Millisecond * time.Duration(rand.Intn(1000)) | |
select { | |
case <-time.After(ms): | |
if rand.Intn(100) > 50 { | |
return fmt.Errorf("work %v failed", i) | |
} | |
fmt.Printf("work %v done\n", i) | |
return nil | |
case <-ctx.Done(): | |
fmt.Printf("work %v canceled...\n", i) | |
return ctx.Err() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment