Files
tasks/common/quotas/dynamic_rate_limiter_impl_test.go
Bojan JanjatovićandGitHub d2511ddc00 Refresh dynamic rate limiter getters (#10099)
**What changed?**

`DynamicRateLimiterImpl.Rate()` and `Burst()` now call `maybeRefresh()`
before returning the underlying limiter values.

**Why?**

`DynamicRateLimiterImpl` already refreshes before token operations such
as `Allow`, `Reserve`, and `Wait`, but direct `Rate()` / `Burst()` calls
could keep returning stale cached values after the refresh interval.

This matters when a dynamic rate limiter is used through the `RateBurst`
surface, which was called out as a follow-up in #4934.

Fixes #4934.

**How did you test it?**

```bash
GOWORK=off GOCACHE=/tmp/go-build-cache go test ./common/quotas
GOWORK=off GOCACHE=/tmp/go-build-cache go test ./common/quotas -run TestDynamicRateLimiterRateAndBurstRefreshAfterInterval -count=20
GOWORK=off GOCACHE=/tmp/go-build-cache go test -race ./common/quotas -run TestDynamicRateLimiterRateAndBurstRefreshAfterInterval -count=20
```

**Potential risks**

Low. This makes getter behavior consistent with existing dynamic limiter
token operations. The refresh path is already used by the limiter's main
operation methods.

**Is hotfix candidate?**

No.
2026-04-29 09:25:54 +00:00

62 lines
1.5 KiB
Go

package quotas_test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"go.temporal.io/server/common/quotas"
)
func TestDynamicRateLimiterRateAndBurstRefreshAfterInterval(t *testing.T) {
t.Parallel()
const (
refreshInterval = 50 * time.Millisecond
initialRate = 10.0
initialBurst = 20
updatedRate = 30.0
updatedBurst = 40
nextRate = 50.0
nextBurst = 60
)
t.Run("rate_refreshes_without_token_operation", func(t *testing.T) {
rateBurst := quotas.NewMutableRateBurst(initialRate, initialBurst)
limiter := quotas.NewDynamicRateLimiter(rateBurst, refreshInterval)
require.InDelta(t, initialRate, limiter.Rate(), 1e-9)
rateBurst.SetRPS(updatedRate)
rateBurst.SetBurst(updatedBurst)
require.Eventually(t, func() bool {
return limiter.Rate() == updatedRate
}, time.Second, 5*time.Millisecond)
rateBurst.SetRPS(nextRate)
rateBurst.SetBurst(nextBurst)
require.InDelta(t, updatedRate, limiter.Rate(), 1e-9)
})
t.Run("burst_refreshes_without_token_operation", func(t *testing.T) {
rateBurst := quotas.NewMutableRateBurst(initialRate, initialBurst)
limiter := quotas.NewDynamicRateLimiter(rateBurst, refreshInterval)
require.Equal(t, initialBurst, limiter.Burst())
rateBurst.SetRPS(updatedRate)
rateBurst.SetBurst(updatedBurst)
require.Eventually(t, func() bool {
return limiter.Burst() == updatedBurst
}, time.Second, 5*time.Millisecond)
rateBurst.SetRPS(nextRate)
rateBurst.SetBurst(nextBurst)
require.Equal(t, updatedBurst, limiter.Burst())
})
}