Skip to content

Commit 263c266

Browse files
authored
Adding lo.WaitFor (#269)
* feat(concurrency): adding lo.WaitFor
1 parent 33853f5 commit 263c266

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ Concurrency helpers:
273273
- [Synchronize](#synchronize)
274274
- [Async](#async)
275275
- [Transaction](#transaction)
276+
- [WaitFor](#waitfor)
276277

277278
Error handling:
278279

@@ -3004,6 +3005,38 @@ _, _ = transaction.Process(-5)
30043005
// rollback 1
30053006
```
30063007

3008+
### WaitFor
3009+
3010+
Runs periodically until a condition is validated.
3011+
3012+
```go
3013+
alwaysTrue := func(i int) bool { return true }
3014+
alwaysFalse := func(i int) bool { return false }
3015+
laterTrue := func(i int) bool {
3016+
return i > 5
3017+
}
3018+
3019+
iterations, duration, ok := lo.WaitFor(alwaysTrue, 10*time.Millisecond, time.Millisecond)
3020+
// 1
3021+
// 0ms
3022+
// true
3023+
3024+
iterations, duration, ok := lo.WaitFor(alwaysFalse, 10*time.Millisecond, time.Millisecond)
3025+
// 10
3026+
// 10ms
3027+
// false
3028+
3029+
iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, time.Millisecond)
3030+
// 7
3031+
// 7ms
3032+
// true
3033+
3034+
iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, 5*time.Millisecond)
3035+
// 2
3036+
// 10ms
3037+
// false
3038+
```
3039+
30073040
### Validate
30083041

30093042
Helper function that creates an error when a condition is not met.

concurrency.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package lo
22

3-
import "sync"
3+
import (
4+
"sync"
5+
"time"
6+
)
47

58
type synchronize struct {
69
locker sync.Locker
@@ -93,3 +96,35 @@ func Async6[A, B, C, D, E, F any](f func() (A, B, C, D, E, F)) <-chan Tuple6[A,
9396
}()
9497
return ch
9598
}
99+
100+
// WaitFor runs periodically until a condition is validated.
101+
func WaitFor(condition func(i int) bool, maxDuration time.Duration, tick time.Duration) (int, time.Duration, bool) {
102+
if condition(0) {
103+
return 1, 0, true
104+
}
105+
106+
start := time.Now()
107+
108+
timer := time.NewTimer(maxDuration)
109+
ticker := time.NewTicker(tick)
110+
111+
defer func() {
112+
timer.Stop()
113+
ticker.Stop()
114+
}()
115+
116+
i := 1
117+
118+
for {
119+
select {
120+
case <-timer.C:
121+
return i, time.Since(start), false
122+
case <-ticker.C:
123+
if condition(i) {
124+
return i + 1, time.Since(start), true
125+
}
126+
127+
i++
128+
}
129+
}
130+
}

concurrency_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,47 @@ func TestAsyncX(t *testing.T) {
212212
}
213213
}
214214
}
215+
216+
func TestWaitFor(t *testing.T) {
217+
t.Parallel()
218+
testWithTimeout(t, 100*time.Millisecond)
219+
is := assert.New(t)
220+
221+
alwaysTrue := func(i int) bool { return true }
222+
alwaysFalse := func(i int) bool { return false }
223+
224+
iter, duration, ok := WaitFor(alwaysTrue, 10*time.Millisecond, time.Millisecond)
225+
is.Equal(1, iter)
226+
is.Equal(time.Duration(0), duration)
227+
is.True(ok)
228+
iter, duration, ok = WaitFor(alwaysFalse, 10*time.Millisecond, 4*time.Millisecond)
229+
is.Equal(3, iter)
230+
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
231+
is.False(ok)
232+
233+
laterTrue := func(i int) bool {
234+
return i >= 5
235+
}
236+
237+
iter, duration, ok = WaitFor(laterTrue, 10*time.Millisecond, time.Millisecond)
238+
is.Equal(6, iter)
239+
is.InEpsilon(6*time.Millisecond, duration, float64(500*time.Microsecond))
240+
is.True(ok)
241+
iter, duration, ok = WaitFor(laterTrue, 10*time.Millisecond, 5*time.Millisecond)
242+
is.Equal(2, iter)
243+
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
244+
is.False(ok)
245+
246+
counter := 0
247+
248+
alwaysFalse = func(i int) bool {
249+
is.Equal(counter, i)
250+
counter++
251+
return false
252+
}
253+
254+
iter, duration, ok = WaitFor(alwaysFalse, 10*time.Millisecond, time.Millisecond)
255+
is.Equal(10, iter)
256+
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
257+
is.False(ok)
258+
}

0 commit comments

Comments
 (0)