Created
January 19, 2025 14:20
-
-
Save threadedstream/3c04bfcd8c16fdcd45c18533b3755736 to your computer and use it in GitHub Desktop.
RateLimiter implemented using SlidingWindow algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"sync" | |
"sync/atomic" | |
"time" | |
) | |
type RateLimiter struct { | |
q []*atomic.Int64 | |
commitedReqs, limit int64 | |
mu sync.RWMutex | |
} | |
// NewRateLimiter returns fresh instance of RateLimiter | |
func NewRateLimiter(limit int64) *RateLimiter { | |
rl := &RateLimiter{ | |
q: make([]*atomic.Int64, 0, 60), | |
limit: limit, | |
} | |
start := time.Now().Unix() | |
end := start + 60 | |
for start < end { | |
rl.q = append(rl.q, &atomic.Int64{}) | |
start++ | |
} | |
go rl.clean() | |
return rl | |
} | |
func (rl *RateLimiter) clean() { | |
ticker := time.NewTicker(time.Second) | |
defer ticker.Stop() | |
select { | |
case <-ticker.C: | |
rl.flushBucket() | |
} | |
} | |
func (rl *RateLimiter) flushBucket() { | |
rl.mu.Lock() | |
defer rl.mu.Unlock() | |
el := rl.q[0] | |
rl.q = rl.q[1:] | |
rl.commitedReqs -= el.Load() | |
rl.q = append(rl.q, el) | |
} | |
func (rl *RateLimiter) Limit() bool { | |
bucket := rl.q[time.Now().Unix()%int64(time.Minute.Seconds())] | |
rl.mu.RLock() | |
if rl.commitedReqs >= rl.limit { | |
rl.mu.RUnlock() | |
return false | |
} | |
rl.mu.RUnlock() | |
// update number of bucket requests | |
bucket.Add(1) | |
rl.mu.Lock() | |
defer rl.mu.Unlock() | |
rl.commitedReqs++ | |
return true | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment