Skip to content

Commit 21ce69f

Browse files
committed
fix: use time.NewTicker in rateLimiter to prevent goroutine leak
1 parent 97a0854 commit 21ce69f

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

api.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,15 @@ type rateLimiter struct {
333333
buckets map[string]*rateBucket
334334
limit int
335335
window time.Duration
336+
done chan struct{}
336337
}
337338

338339
func newRateLimiter(limit int) *rateLimiter {
339340
rl := &rateLimiter{
340341
buckets: make(map[string]*rateBucket),
341342
limit: limit,
342343
window: time.Minute,
344+
done: make(chan struct{}),
343345
}
344346
go rl.cleanup()
345347
return rl
@@ -362,18 +364,29 @@ func (rl *rateLimiter) allow(ip string) bool {
362364
}
363365

364366
func (rl *rateLimiter) cleanup() {
365-
for range time.Tick(10 * time.Minute) {
366-
rl.mu.Lock()
367-
now := time.Now()
368-
for ip, b := range rl.buckets {
369-
if now.After(b.resetAt) {
370-
delete(rl.buckets, ip)
367+
ticker := time.NewTicker(10 * time.Minute)
368+
defer ticker.Stop()
369+
for {
370+
select {
371+
case <-ticker.C:
372+
rl.mu.Lock()
373+
now := time.Now()
374+
for ip, b := range rl.buckets {
375+
if now.After(b.resetAt) {
376+
delete(rl.buckets, ip)
377+
}
371378
}
379+
rl.mu.Unlock()
380+
case <-rl.done:
381+
return
372382
}
373-
rl.mu.Unlock()
374383
}
375384
}
376385

386+
func (rl *rateLimiter) stop() {
387+
close(rl.done)
388+
}
389+
377390
func rateLimitMiddleware(rl *rateLimiter, next httprouter.Handle) httprouter.Handle {
378391
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
379392
if rl == nil {

api_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ func TestRegisterRateLimit(t *testing.T) {
621621
Config.API.HeaderName = "X-Forwarded-For"
622622

623623
limiter := newRateLimiter(Config.API.RegisterRateLimit)
624+
defer limiter.stop()
624625

625626
api2 := httprouter.New()
626627
api2.POST("/register", rateLimitMiddleware(limiter, webRegisterPost))

0 commit comments

Comments
 (0)