renamed outdated rate limit struct name and added reminder to reavulate the algorithm

This commit is contained in:
Gani Georgiev 2025-11-18 22:23:59 +02:00
parent 91f1ca273d
commit 6500b8c518
1 changed files with 17 additions and 11 deletions

View File

@ -234,12 +234,12 @@ func newRateLimiter(maxAllowed int, intervalInSec int64, minDeleteIntervalInSec
maxAllowed: maxAllowed, maxAllowed: maxAllowed,
interval: intervalInSec, interval: intervalInSec,
minDeleteInterval: minDeleteIntervalInSec, minDeleteInterval: minDeleteIntervalInSec,
clients: map[string]*fixedWindow{}, clients: map[string]*rateClient{},
} }
} }
type rateLimiter struct { type rateLimiter struct {
clients map[string]*fixedWindow clients map[string]*rateClient
maxAllowed int maxAllowed int
interval int64 interval int64
@ -250,7 +250,7 @@ type rateLimiter struct {
} }
//nolint:unused //nolint:unused
func (rt *rateLimiter) getClient(key string) (*fixedWindow, bool) { func (rt *rateLimiter) getClient(key string) (*rateClient, bool) {
rt.RLock() rt.RLock()
client, ok := rt.clients[key] client, ok := rt.clients[key]
rt.RUnlock() rt.RUnlock()
@ -269,7 +269,7 @@ func (rt *rateLimiter) isAllowed(key string) bool {
// check again in case the client was added by another request // check again in case the client was added by another request
client, ok = rt.clients[key] client, ok = rt.clients[key]
if !ok { if !ok {
client = newFixedWindow(rt.maxAllowed, rt.interval) client = newRateClient(rt.maxAllowed, rt.interval)
rt.clients[key] = client rt.clients[key] = client
} }
rt.Unlock() rt.Unlock()
@ -295,7 +295,7 @@ func (rt *rateLimiter) clean() {
// //
// @todo remove after https://github.com/golang/go/issues/20135 // @todo remove after https://github.com/golang/go/issues/20135
if rt.totalDeleted >= 300 { if rt.totalDeleted >= 300 {
shrunk := make(map[string]*fixedWindow, len(rt.clients)) shrunk := make(map[string]*rateClient, len(rt.clients))
for k, v := range rt.clients { for k, v := range rt.clients {
shrunk[k] = v shrunk[k] = v
} }
@ -304,14 +304,20 @@ func (rt *rateLimiter) clean() {
} }
} }
func newFixedWindow(maxAllowed int, intervalInSec int64) *fixedWindow { func newRateClient(maxAllowed int, intervalInSec int64) *rateClient {
return &fixedWindow{ return &rateClient{
maxAllowed: maxAllowed, maxAllowed: maxAllowed,
interval: intervalInSec, interval: intervalInSec,
} }
} }
type fixedWindow struct { // @todo evaluate swiching to a more traditional fixed window or sliding window counter
// implementations since some users complained that it is not intuitive (see #7329).
//
// rateClient is a mixture of token bucket and fixed window rate limit strategies
// that refills the allowance only after at least "interval" seconds
// has elapsed since the last request.
type rateClient struct {
// use plain Mutex instead of RWMutex since the operations are expected // use plain Mutex instead of RWMutex since the operations are expected
// to be mostly writes (e.g. consume()) and it should perform better // to be mostly writes (e.g. consume()) and it should perform better
sync.Mutex sync.Mutex
@ -324,18 +330,18 @@ type fixedWindow struct {
// hasExpired checks whether it has been at least minElapsed seconds since the lastConsume time. // hasExpired checks whether it has been at least minElapsed seconds since the lastConsume time.
// (usually used to perform periodic cleanup of staled instances). // (usually used to perform periodic cleanup of staled instances).
func (l *fixedWindow) hasExpired(relativeNow int64, minElapsed int64) bool { func (l *rateClient) hasExpired(relativeNow int64, minElapsed int64) bool {
l.Lock() l.Lock()
defer l.Unlock() defer l.Unlock()
return relativeNow-l.lastConsume > minElapsed return relativeNow-l.lastConsume > minElapsed
} }
// consume decrease the current window allowance with 1 (if not exhausted already). // consume decreases the current allowance with 1 (if not exhausted already).
// //
// It returns false if the allowance has been already exhausted and the user // It returns false if the allowance has been already exhausted and the user
// has to wait until it resets back to its maxAllowed value. // has to wait until it resets back to its maxAllowed value.
func (l *fixedWindow) consume() bool { func (l *rateClient) consume() bool {
l.Lock() l.Lock()
defer l.Unlock() defer l.Unlock()