-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsliding_window.go
More file actions
59 lines (50 loc) · 1.8 KB
/
Copy pathsliding_window.go
File metadata and controls
59 lines (50 loc) · 1.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package rate_limiter
import (
"sync"
"time"
)
// SlidingWindowLog limits traffic smoothly over a timeframe.
// Unlike traditional "Token Buckets" which permit sudden bursts, sliding windows
// offer perfectly distributed limits but consume slightly more memory tracking timestamps.
type SlidingWindowLog struct {
mu sync.Mutex // Extremely critical in traffic gateways!
timestamps []time.Time // Slice storing exact moments requests occurred.
windowSize time.Duration // E.g., 10 seconds.
capacity int // Max requests allowed during the Window.
}
func NewSlidingWindowLog(size time.Duration, cap int) *SlidingWindowLog {
return &SlidingWindowLog{
timestamps: make([]time.Time, 0, cap), // Pre-allocating to avoid runtime allocations
windowSize: size,
capacity: cap,
}
}
// Allow processes an incoming API request. True = Proceed, False = Rate Limit (HTTP 429).
func (s *SlidingWindowLog) Allow() bool {
// A high throughput ingress node will have tens of thousands of Goroutines slamming this mutex.
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now()
boundary := now.Add(-s.windowSize)
// In a real optimized system, we could binary search to find the cut-off index,
// but simple iteration from the start (oldest logs) is fast enough for localized windows.
cutoffIdx := 0
for i, t := range s.timestamps {
if t.After(boundary) {
cutoffIdx = i
break
}
}
// Fast memory shift: Slice out the ancient timestamps falling outside our window boundary!
if cutoffIdx > 0 {
s.timestamps = s.timestamps[cutoffIdx:]
}
// Make the decision
if len(s.timestamps) < s.capacity {
// Valid Request! We append the timestamp.
s.timestamps = append(s.timestamps, now)
return true
}
// Gateway Throttled us! Proxy must intercept and return HTTP 429 Too Many Requests.
return false
}