Skip to content

Commit 669ebf4

Browse files
committed
fn: stress test GoroutineManager.Stop calls
Make sure there is no race condition between Done() and Wait() methods in the GoroutineManager implementation. See #9141 (comment)
1 parent 0876173 commit 669ebf4

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

fn/goroutine_manager_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fn
22

33
import (
44
"context"
5+
"sync"
56
"testing"
67
"time"
78

@@ -119,3 +120,38 @@ func TestGoroutineManagerStress(t *testing.T) {
119120
// Wait for Stop to complete.
120121
<-stopChan
121122
}
123+
124+
// TestGoroutineManagerStopsStress launches many Stop() calls in parallel with a
125+
// task exiting. It attempts to catch a race condition between wg.Done() and
126+
// wg.Wait() calls. According to documentation of wg.Wait() this is acceptable,
127+
// therefore this test passes even with -race.
128+
func TestGoroutineManagerStopsStress(t *testing.T) {
129+
t.Parallel()
130+
131+
m := NewGoroutineManager(context.Background())
132+
133+
// jobChan is used to make the task to finish.
134+
jobChan := make(chan struct{})
135+
136+
// Start a task and wait inside it until we start calling Stop() method.
137+
err := m.Go(func(ctx context.Context) {
138+
<-jobChan
139+
})
140+
require.NoError(t, err)
141+
142+
// Now launch many gorotines calling Stop() method in parallel.
143+
var wg sync.WaitGroup
144+
for i := 0; i < 100; i++ {
145+
wg.Add(1)
146+
go func() {
147+
defer wg.Done()
148+
m.Stop()
149+
}()
150+
}
151+
152+
// Exit the task in parallel with Stop() calls.
153+
close(jobChan)
154+
155+
// Wait until all the Stop() calls complete.
156+
wg.Wait()
157+
}

0 commit comments

Comments
 (0)