mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-10 16:30:01 +08:00
fix: resolve concurrent get may lead to empty result in ImmutableResource (#5065)
Co-authored-by: hsun <hsun@apac.freewheel.com> Co-authored-by: Kevin Wan <wanjunfeng@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -2,6 +2,8 @@ package syncx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -56,6 +58,46 @@ func TestImmutableResourceError(t *testing.T) {
|
||||
assert.Equal(t, 2, count)
|
||||
}
|
||||
|
||||
func TestImmutableResourceConcurrent(t *testing.T) {
|
||||
var count int32
|
||||
ready := make(chan struct{})
|
||||
r := NewImmutableResource(func() (any, error) {
|
||||
atomic.AddInt32(&count, 1)
|
||||
close(ready) // signal that fetch started
|
||||
time.Sleep(10 * time.Millisecond) // simulate slow fetch
|
||||
return "hello", nil
|
||||
})
|
||||
|
||||
const goroutines = 100
|
||||
var wg sync.WaitGroup
|
||||
results := make([]any, goroutines)
|
||||
errors := make([]error, goroutines)
|
||||
|
||||
wg.Add(goroutines)
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
res, err := r.Get()
|
||||
results[idx] = res
|
||||
errors[idx] = err
|
||||
}(i)
|
||||
}
|
||||
|
||||
// wait for fetch to start
|
||||
<-ready
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// fetch should only be called once despite concurrent access
|
||||
assert.Equal(t, int32(1), atomic.LoadInt32(&count))
|
||||
|
||||
// all goroutines should eventually get the same result
|
||||
for i := 0; i < goroutines; i++ {
|
||||
assert.Nil(t, errors[i])
|
||||
assert.Equal(t, "hello", results[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestImmutableResourceErrorRefreshAlways(t *testing.T) {
|
||||
var count int
|
||||
r := NewImmutableResource(func() (any, error) {
|
||||
|
||||
Reference in New Issue
Block a user