diff options
Diffstat (limited to 'utils/ratelimit/limiter.go')
| -rw-r--r-- | utils/ratelimit/limiter.go | 96 |
1 files changed, 29 insertions, 67 deletions
diff --git a/utils/ratelimit/limiter.go b/utils/ratelimit/limiter.go index 6450c8b..c99a935 100644 --- a/utils/ratelimit/limiter.go +++ b/utils/ratelimit/limiter.go @@ -5,80 +5,40 @@ import ( ) func NewRateLimiter(maxRequests int, window time.Duration) *RateLimiter { - minDelay := window / time.Duration(maxRequests) - return &RateLimiter{ - lastRequests: make([]time.Time, 0, maxRequests), - maxRequests: maxRequests, - window: window, - minDelay: minDelay, - } + interval := window / time.Duration(maxRequests) + rl := &RateLimiter{ + tokens: make(chan struct{}, maxRequests), + done: make(chan struct{}), + } + rl.tokens <- struct{}{} + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + for { + select { + case <-ticker.C: + select { + case rl.tokens <- struct{}{}: + default: + } + case <-rl.done: + return + } + } + }() + return rl } func (r *RateLimiter) Wait() { - r.mu.Lock() - defer r.mu.Unlock() - - now := time.Now() - - if !r.lastRequest.IsZero() { - elapsed := now.Sub(r.lastRequest) - if elapsed < r.minDelay { - waitTime := r.minDelay - elapsed - r.mu.Unlock() - time.Sleep(waitTime) - r.mu.Lock() - now = time.Now() - } - } - - cutoff := now.Add(-r.window) - i := 0 - for i < len(r.lastRequests) && r.lastRequests[i].Before(cutoff) { - i++ - } - if i > 0 { - r.lastRequests = r.lastRequests[i:] - } - - if len(r.lastRequests) >= r.maxRequests { - oldestInWindow := r.lastRequests[0] - waitDuration := r.window - now.Sub(oldestInWindow) - - r.mu.Unlock() - time.Sleep(waitDuration + time.Millisecond) - r.mu.Lock() - - now = time.Now() - cutoff = now.Add(-r.window) - i = 0 - for i < len(r.lastRequests) && r.lastRequests[i].Before(cutoff) { - i++ - } - if i > 0 { - r.lastRequests = r.lastRequests[i:] - } - } + <-r.tokens +} - r.lastRequest = now - r.lastRequests = append(r.lastRequests, now) +func (r *RateLimiter) Stop() { + close(r.done) } func (r *RateLimiter) RemainingRequests() int { - r.mu.Lock() - defer r.mu.Unlock() - - now := time.Now() - cutoff := now.Add(-r.window) - - i := 0 - for i < len(r.lastRequests) && r.lastRequests[i].Before(cutoff) { - i++ - } - if i > 0 { - r.lastRequests = r.lastRequests[i:] - } - - return r.maxRequests - len(r.lastRequests) + return len(r.tokens) } func NewMultiLimiter(limiters ...*RateLimiter) *MultiLimiter { @@ -88,6 +48,8 @@ func NewMultiLimiter(limiters ...*RateLimiter) *MultiLimiter { } func (m *MultiLimiter) Wait() { + m.mu.Lock() + defer m.mu.Unlock() for _, limiter := range m.limiters { limiter.Wait() } |
