Skip to content

Commit db6df8a

Browse files
committed
feat: All return the error and the index of the function.
1 parent d8a57a0 commit db6df8a

File tree

2 files changed

+36
-20
lines changed

2 files changed

+36
-20
lines changed

all.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,31 @@ import (
99
)
1010

1111
// All executes the functions asynchronously until all functions have been finished. If some
12-
// function returns an error or panic, it will return the error immediately and send a cancel
13-
// signal to all other functions by context.
14-
func All(funcs ...func(context.Context) error) error {
12+
// function returns an error or panic, it will immediately return the index of the function and the
13+
// error, and send a cancel signal to all other functions by context.
14+
//
15+
// The index of the function will be -1 if all functions have been completed without error or
16+
// panic.
17+
func All(funcs ...func(context.Context) error) (int, error) {
1518
return all(context.Background(), funcs...)
1619
}
1720

1821
// AllWithContext executes the functions asynchronously until all functions have been finished, or
1922
// the context is done (canceled or timeout). If some function returns an error or panic, it will
20-
// return the error immediately and send a cancel signal to all other functions by context.
21-
func AllWithContext(ctx context.Context, funcs ...func(context.Context) error) error {
23+
// immediately return the index of the index and the error and send a cancel signal to all other
24+
// functions by context.
25+
//
26+
// The index of the function will be -1 if all functions have been completed without error or
27+
// panic, or the context has been canceled (or timeout) before all functions finished.
28+
func AllWithContext(ctx context.Context, funcs ...func(context.Context) error) (int, error) {
2229
return all(ctx, funcs...)
2330
}
2431

2532
// all executes the functions asynchronously until all functions have been finished, or the context
2633
// is done (canceled or timeout).
27-
func all(parent context.Context, funcs ...func(context.Context) error) error {
34+
func all(parent context.Context, funcs ...func(context.Context) error) (int, error) {
2835
if len(funcs) == 0 {
29-
return nil
36+
return -1, nil
3037
}
3138

3239
if parent == nil {
@@ -36,11 +43,12 @@ func all(parent context.Context, funcs ...func(context.Context) error) error {
3643
ctx, canFunc := context.WithCancel(parent)
3744
defer canFunc()
3845

39-
errCh := make(chan error)
40-
defer close(errCh)
46+
ch := make(chan executeResult)
47+
defer close(ch)
4148

4249
for i := 0; i < len(funcs); i++ {
4350
fn := funcs[i]
51+
n := i
4452
go func() {
4553
childCtx, childCanFunc := context.WithCancel(ctx)
4654
defer childCanFunc()
@@ -53,7 +61,10 @@ func all(parent context.Context, funcs ...func(context.Context) error) error {
5361
case <-ctx.Done():
5462
return
5563
default:
56-
errCh <- err
64+
ch <- executeResult{
65+
Error: err,
66+
Index: n,
67+
}
5768
}
5869
}()
5970
}
@@ -62,16 +73,16 @@ func all(parent context.Context, funcs ...func(context.Context) error) error {
6273
for finished < len(funcs) {
6374
select {
6475
case <-parent.Done():
65-
return errors.New("context canceled")
66-
case err := <-errCh:
67-
if err != nil {
68-
return err
76+
return -1, errors.New("context canceled")
77+
case ret := <-ch:
78+
if ret.Error != nil {
79+
return ret.Index, ret.Error
6980
}
7081
finished++
7182
}
7283
}
7384

74-
return nil
85+
return -1, nil
7586
}
7687

7788
// AllCompleted executes the functions asynchronously until all functions have been finished. It

all_test.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212
func TestAllWithoutFuncs(t *testing.T) {
1313
a := assert.New(t)
1414

15-
err := All()
15+
index, err := All()
1616
a.NilNow(err)
17+
a.EqualNow(index, -1)
1718
}
1819

1920
func TestAllSuccess(t *testing.T) {
@@ -30,8 +31,9 @@ func TestAllSuccess(t *testing.T) {
3031
})
3132
}
3233

33-
err := All(funcs...)
34+
index, err := All(funcs...)
3435
a.NilNow(err)
36+
a.EqualNow(index, -1)
3537
a.EqualNow(data, []bool{true, true, true, true, true})
3638
}
3739

@@ -52,8 +54,9 @@ func TestAllFailure(t *testing.T) {
5254
})
5355
}
5456

55-
err := All(funcs...)
57+
index, err := All(funcs...)
5658
a.NotNilNow(err)
59+
a.EqualNow(index, 2)
5760
a.EqualNow(err.Error(), "n = 2")
5861
a.EqualNow(data, []bool{true, true, false, false, false})
5962
}
@@ -62,11 +65,12 @@ func TestAllWithNilContext(t *testing.T) {
6265
a := assert.New(t)
6366

6467
//lint:ignore SA1012 for test case only
65-
err := AllWithContext(nil, func(ctx context.Context) error {
68+
index, err := AllWithContext(nil, func(ctx context.Context) error {
6669
time.Sleep(100 * time.Millisecond)
6770
return nil
6871
})
6972
a.NilNow(err)
73+
a.EqualNow(index, -1)
7074
}
7175

7276
func TestAllWithTimeoutContext(t *testing.T) {
@@ -86,8 +90,9 @@ func TestAllWithTimeoutContext(t *testing.T) {
8690
ctx, canFunc := context.WithTimeout(context.Background(), 150*time.Millisecond)
8791
defer canFunc()
8892

89-
err := AllWithContext(ctx, funcs...)
93+
index, err := AllWithContext(ctx, funcs...)
9094
a.NotNilNow(err)
95+
a.EqualNow(index, -1)
9196
a.Equal(err.Error(), "context canceled")
9297
a.EqualNow(data, []bool{true, true, false, false, false})
9398
}

0 commit comments

Comments
 (0)