Adding lo.WaitFor (#269)

* feat(concurrency): adding lo.WaitFor
This commit is contained in:
Samuel Berthe
2024-06-28 22:00:52 +02:00
committed by GitHub
parent 33853f5d82
commit 263c266328
3 changed files with 113 additions and 1 deletions

View File

@@ -273,6 +273,7 @@ Concurrency helpers:
- [Synchronize](#synchronize)
- [Async](#async)
- [Transaction](#transaction)
- [WaitFor](#waitfor)
Error handling:
@@ -3004,6 +3005,38 @@ _, _ = transaction.Process(-5)
// rollback 1
```
### WaitFor
Runs periodically until a condition is validated.
```go
alwaysTrue := func(i int) bool { return true }
alwaysFalse := func(i int) bool { return false }
laterTrue := func(i int) bool {
return i > 5
}
iterations, duration, ok := lo.WaitFor(alwaysTrue, 10*time.Millisecond, time.Millisecond)
// 1
// 0ms
// true
iterations, duration, ok := lo.WaitFor(alwaysFalse, 10*time.Millisecond, time.Millisecond)
// 10
// 10ms
// false
iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, time.Millisecond)
// 7
// 7ms
// true
iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, 5*time.Millisecond)
// 2
// 10ms
// false
```
### Validate
Helper function that creates an error when a condition is not met.

View File

@@ -1,6 +1,9 @@
package lo
import "sync"
import (
"sync"
"time"
)
type synchronize struct {
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,
}()
return ch
}
// WaitFor runs periodically until a condition is validated.
func WaitFor(condition func(i int) bool, maxDuration time.Duration, tick time.Duration) (int, time.Duration, bool) {
if condition(0) {
return 1, 0, true
}
start := time.Now()
timer := time.NewTimer(maxDuration)
ticker := time.NewTicker(tick)
defer func() {
timer.Stop()
ticker.Stop()
}()
i := 1
for {
select {
case <-timer.C:
return i, time.Since(start), false
case <-ticker.C:
if condition(i) {
return i + 1, time.Since(start), true
}
i++
}
}
}

View File

@@ -212,3 +212,47 @@ func TestAsyncX(t *testing.T) {
}
}
}
func TestWaitFor(t *testing.T) {
t.Parallel()
testWithTimeout(t, 100*time.Millisecond)
is := assert.New(t)
alwaysTrue := func(i int) bool { return true }
alwaysFalse := func(i int) bool { return false }
iter, duration, ok := WaitFor(alwaysTrue, 10*time.Millisecond, time.Millisecond)
is.Equal(1, iter)
is.Equal(time.Duration(0), duration)
is.True(ok)
iter, duration, ok = WaitFor(alwaysFalse, 10*time.Millisecond, 4*time.Millisecond)
is.Equal(3, iter)
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
is.False(ok)
laterTrue := func(i int) bool {
return i >= 5
}
iter, duration, ok = WaitFor(laterTrue, 10*time.Millisecond, time.Millisecond)
is.Equal(6, iter)
is.InEpsilon(6*time.Millisecond, duration, float64(500*time.Microsecond))
is.True(ok)
iter, duration, ok = WaitFor(laterTrue, 10*time.Millisecond, 5*time.Millisecond)
is.Equal(2, iter)
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
is.False(ok)
counter := 0
alwaysFalse = func(i int) bool {
is.Equal(counter, i)
counter++
return false
}
iter, duration, ok = WaitFor(alwaysFalse, 10*time.Millisecond, time.Millisecond)
is.Equal(10, iter)
is.InEpsilon(10*time.Millisecond, duration, float64(500*time.Microsecond))
is.False(ok)
}