Skip to content

Commit aec4f90

Browse files
Merge pull request #101 from mftee/feat/api-rate-limiting
feat(ratelimit): add token-bucket API rate limiter
2 parents 953e0ad + 78735b5 commit aec4f90

1 file changed

Lines changed: 49 additions & 0 deletions

File tree

internal/ratelimit/ratelimit.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Package ratelimit implements a token-bucket limiter to protect API
2+
// endpoints from abuse.
3+
package ratelimit
4+
5+
import (
6+
"sync"
7+
"time"
8+
)
9+
10+
// Limiter is a token-bucket rate limiter safe for concurrent use.
11+
type Limiter struct {
12+
mu sync.Mutex
13+
tokens float64
14+
capacity float64
15+
refillRate float64
16+
last time.Time
17+
}
18+
19+
// NewLimiter returns a Limiter that allows up to capacity requests in a
20+
// burst, refilling at refillRate tokens per second.
21+
func NewLimiter(capacity, refillRate float64) *Limiter {
22+
return &Limiter{
23+
tokens: capacity,
24+
capacity: capacity,
25+
refillRate: refillRate,
26+
last: time.Now(),
27+
}
28+
}
29+
30+
// Allow reports whether a single request may proceed now, consuming one
31+
// token if so.
32+
func (l *Limiter) Allow() bool {
33+
l.mu.Lock()
34+
defer l.mu.Unlock()
35+
36+
now := time.Now()
37+
elapsed := now.Sub(l.last).Seconds()
38+
l.last = now
39+
40+
l.tokens += elapsed * l.refillRate
41+
if l.tokens > l.capacity {
42+
l.tokens = l.capacity
43+
}
44+
if l.tokens < 1 {
45+
return false
46+
}
47+
l.tokens--
48+
return true
49+
}

0 commit comments

Comments
 (0)