There is a code:
func main() {
rand.Seed(time.Now().UnixNano())
res, err := MockFunc()
fmt.Printf("res - %v, err - %v\n", res, err)
}
func MockFunc() ([]int, error) {
args := []int{1, 2, 3, 4, 5}
result := make([]int, 0)
errCh := make(chan error)
wg := &sync.WaitGroup{}
wg.Add(len(args))
for _, a := range args {
go func(aLit int) {
value, err := RandomError(aLit)
if err != nil {
errCh <- err
return
}
result = append(result, value)
}(a)
}
errValue := <-errCh // if no errors, i have panic - fatal error: all goroutines are asleep - deadlock!
if errValue != nil {
fmt.Println("returning because err")
return nil, errValue // if RandomError() returns error, returned here as expected
}
wg.Wait()
return result, nil
}
func RandomError(arg int) (int, error) {
time.Sleep(time.Millisecond * 100 * time.Duration(arg))
errChance := rand.Intn(100)
if errChance > 40 {
fmt.Printf("error on arg - %d\n", arg)
return 0, errors.New("mock err")
}
return errChance, nil
}
I need that if the RandomError() function returns an error, then the MockFunc() function completed before waiting for all waitgroups and returned an error. But if there are no errors, then I get a deadlock, if there is, then everything works as expected.
I understand that this is because I am not closing the channel. But if I close it after wg.Wait(), then the meaning of this will be lost, since if the first call to the function returned an error, then I will wait for the results of all the other calls.
I need it so that if one of the calls to RandomeErr() returned an error, I returned this error from MockFunc() to main() without waiting for the end of all calls.