diff --git a/retry.go b/retry.go index 0f548ef..73eeda8 100644 --- a/retry.go +++ b/retry.go @@ -39,10 +39,9 @@ func LimitRetry(s RetryStrategy, max int) RetryStrategy { } func (r *limitedRetry) NextBackoff() time.Duration { - if r.cnt.Load() >= r.max { + if r.cnt.Add(1) > r.max { return 0 } - r.cnt.Add(1) return r.s.NextBackoff() } diff --git a/retry_test.go b/retry_test.go index fc44fb4..f7a1675 100644 --- a/retry_test.go +++ b/retry_test.go @@ -1,6 +1,8 @@ package redislock_test import ( + "sync" + "sync/atomic" "testing" "time" @@ -60,3 +62,32 @@ func TestLimitRetry(t *testing.T) { } } } + +func TestLimitRetry_concurrent(t *testing.T) { + const ( + max = 100 + callers = 64 + ) + + var allowed atomic.Int64 + retry := LimitRetry(LinearBackoff(time.Millisecond), max) + + var wg sync.WaitGroup + start := make(chan struct{}) + for range callers { + wg.Go(func() { + <-start + for range max { + if retry.NextBackoff() > 0 { + allowed.Add(1) + } + } + }) + } + close(start) + wg.Wait() + + if got := allowed.Load(); got != max { + t.Fatalf("expected exactly %d allowed retries, got %d", max, got) + } +}