Skip to content

Commit bb432b2

Browse files
committed
feat: add AllCompleted.
1 parent 48de8aa commit bb432b2

File tree

2 files changed

+126
-1
lines changed

2 files changed

+126
-1
lines changed

all.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package async
33
import (
44
"context"
55
"errors"
6+
"sync"
67
)
78

89
func All(funcs ...func(context.Context) error) error {
@@ -65,3 +66,44 @@ func all(parent context.Context, funcs ...func(context.Context) error) error {
6566
}
6667
}
6768
}
69+
70+
func AllCompleted(funcs ...func(context.Context) error) ([]error, bool) {
71+
return allCompleted(context.Background(), funcs...)
72+
}
73+
74+
func AllCompletedWithContext(ctx context.Context, funcs ...func(context.Context) error) ([]error, bool) {
75+
return allCompleted(ctx, funcs...)
76+
}
77+
78+
func allCompleted(parent context.Context, funcs ...func(context.Context) error) (errs []error, hasError bool) {
79+
hasError = false
80+
errs = make([]error, len(funcs))
81+
if len(funcs) == 0 {
82+
return
83+
}
84+
85+
wg := sync.WaitGroup{}
86+
wg.Add(len(funcs))
87+
88+
for i := 0; i < len(funcs); i++ {
89+
n := i
90+
fn := funcs[n]
91+
go func() {
92+
childCtx, childCanFunc := context.WithCancel(parent)
93+
defer childCanFunc()
94+
defer wg.Done()
95+
96+
err := executionContainer(func() error {
97+
return fn(childCtx)
98+
})
99+
if err != nil {
100+
hasError = true
101+
errs[n] = err
102+
}
103+
}()
104+
}
105+
106+
wg.Wait()
107+
108+
return
109+
}

all_test.go

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestAllFailure(t *testing.T) {
5858
a.EqualNow(data, []bool{true, true, false, false, false})
5959
}
6060

61-
func TestAllWithTimeoutedContext(t *testing.T) {
61+
func TestAllWithTimeoutContext(t *testing.T) {
6262
a := assert.New(t)
6363

6464
data := make([]bool, 5)
@@ -80,3 +80,86 @@ func TestAllWithTimeoutedContext(t *testing.T) {
8080
a.Equal(err.Error(), "context canceled")
8181
a.EqualNow(data, []bool{true, true, false, false, false})
8282
}
83+
84+
func TestAllCompletedWithoutFuncs(t *testing.T) {
85+
a := assert.New(t)
86+
87+
errs, hasError := AllCompleted()
88+
a.NotTrueNow(hasError)
89+
a.EqualNow(errs, []error{})
90+
}
91+
92+
func TestAllCompletedSuccess(t *testing.T) {
93+
a := assert.New(t)
94+
95+
data := make([]bool, 5)
96+
funcs := make([]func(context.Context) error, 0, 5)
97+
for i := 0; i < 5; i++ {
98+
n := i
99+
funcs = append(funcs, func(ctx context.Context) error {
100+
time.Sleep(time.Duration(n*100) * time.Millisecond)
101+
data[n] = true
102+
return nil
103+
})
104+
}
105+
106+
errs, hasError := AllCompleted(funcs...)
107+
a.NotTrueNow(hasError)
108+
a.EqualNow(data, []bool{true, true, true, true, true})
109+
a.EqualNow(errs, []error{nil, nil, nil, nil, nil})
110+
}
111+
112+
func TestAllCompletedPartialFailure(t *testing.T) {
113+
a := assert.New(t)
114+
115+
errNIs2 := errors.New("n = 2")
116+
117+
data := make([]bool, 5)
118+
funcs := make([]func(context.Context) error, 0, 5)
119+
for i := 0; i < 5; i++ {
120+
n := i
121+
funcs = append(funcs, func(ctx context.Context) error {
122+
time.Sleep(time.Duration(n*100) * time.Millisecond)
123+
if n == 2 {
124+
return errNIs2
125+
}
126+
data[n] = true
127+
return nil
128+
})
129+
}
130+
131+
errs, hasError := AllCompleted(funcs...)
132+
a.TrueNow(hasError)
133+
a.EqualNow(data, []bool{true, true, false, true, true})
134+
a.EqualNow(errs, []error{nil, nil, errNIs2, nil, nil})
135+
}
136+
137+
func TestAllCompletedWithTimeoutContext(t *testing.T) {
138+
a := assert.New(t)
139+
140+
errTimeout := errors.New("timeout")
141+
142+
data := make([]bool, 5)
143+
funcs := make([]func(context.Context) error, 0, 5)
144+
for i := 0; i < 5; i++ {
145+
n := i
146+
funcs = append(funcs, func(ctx context.Context) error {
147+
time.Sleep(time.Duration(n*100) * time.Millisecond)
148+
select {
149+
case <-ctx.Done():
150+
return errTimeout
151+
default:
152+
data[n] = true
153+
return nil
154+
}
155+
})
156+
}
157+
158+
ctx, canFunc := context.WithTimeout(context.Background(), 150*time.Millisecond)
159+
defer canFunc()
160+
161+
errs, hasError := AllCompletedWithContext(ctx, funcs...)
162+
a.TrueNow(hasError)
163+
a.EqualNow(data, []bool{true, true, false, false, false})
164+
a.EqualNow(errs, []error{nil, nil, errTimeout, errTimeout, errTimeout})
165+
}

0 commit comments

Comments
 (0)