Skip to content

Commit

Permalink
fix goroutine leak after calling Future.Get() (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
reugn authored Jul 28, 2023
1 parent 2d4e806 commit a77de92
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
4 changes: 2 additions & 2 deletions future.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var _ Future[any] = (*FutureImpl[any])(nil)
// NewFuture returns a new Future.
func NewFuture[T any]() Future[T] {
return &FutureImpl[T]{
done: make(chan interface{}),
done: make(chan interface{}, 1),
}
}

Expand All @@ -71,7 +71,7 @@ func (fut *FutureImpl[T]) acceptTimeout(timeout time.Duration) {
case result := <-fut.done:
fut.setResult(result)
case <-timer.C:
fut.err = fmt.Errorf("Future timeout after %s", timeout)
fut.setResult(fmt.Errorf("Future timeout after %s", timeout))
}
})
}
Expand Down
36 changes: 36 additions & 0 deletions future_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package async

import (
"errors"
"fmt"
"runtime"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -106,3 +109,36 @@ func TestFutureTimeout(t *testing.T) {
_, err = future.Join()
internal.AssertErrorContains(t, err, "timeout")
}

func TestFutureGoroutineLeak(t *testing.T) {
var wg sync.WaitGroup

fmt.Println(runtime.NumGoroutine())

numFuture := 100
for i := 0; i < numFuture; i++ {
promise := NewPromise[string]()
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(time.Millisecond * 100)
promise.Success("OK")
}()
wg.Add(1)
go func() {
defer wg.Done()
fut := promise.Future()
_, _ = fut.Get(time.Millisecond * 10)
time.Sleep(time.Millisecond * 100)
_, _ = fut.Join()
}()
}

wg.Wait()
time.Sleep(time.Millisecond * 10)
numGoroutine := runtime.NumGoroutine()
fmt.Println(numGoroutine)
if numGoroutine > numFuture {
t.Fatalf("numGoroutine is %d", numGoroutine)
}
}

0 comments on commit a77de92

Please sign in to comment.