Skip to content

Commit 5bf5874

Browse files
authored
🐛 refreshable: fix race condition in ToV2 (#381)
1 parent 3ef9bcc commit 5bf5874

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

refreshable/v2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ func ToV2[T any](v1 Refreshable) refreshablev2.Refreshable[T] {
1515
v1.Subscribe(func(i interface{}) {
1616
v2.Update(i.(T))
1717
})
18+
// If v1 is updated before the subscription above is registered,
19+
// the new v1 would have not propagated to v2.
20+
// Here we enforce v2 has the latest v1.
21+
v2.Update(v1.Current().(T))
1822
return v2
1923
}
2024

refreshable/v2_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
1112
)
1213

1314
func TestToFromV2(t *testing.T) {
@@ -23,3 +24,18 @@ func TestToFromV2(t *testing.T) {
2324
assert.Equal(t, v2.Current(), "updated", "v2 missing updated value")
2425
assert.Equal(t, v1.Current(), "updated", "v1 missing updated value")
2526
}
27+
28+
func TestToV2RespectsUpdates(t *testing.T) {
29+
for i := 0; i < 10000; i++ {
30+
v1 := NewDefaultRefreshable(1)
31+
updateCalled := make(chan struct{})
32+
go func() {
33+
require.NoError(t, v1.Update(2))
34+
close(updateCalled)
35+
}()
36+
v2 := ToV2[int](v1)
37+
<-updateCalled
38+
assert.Equal(t, 2, v2.Current(),
39+
"v2 should always be updated after Update is called")
40+
}
41+
}

0 commit comments

Comments
 (0)