Skip to content

Commit 48b353c

Browse files
authored
Merge pull request #14 from augustus281/sliding
[sliding window]: redis
2 parents fd3cabc + 0fd2ffa commit 48b353c

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,56 @@
11
package algorithms
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"sync"
7+
"time"
8+
9+
"github.com/redis/go-redis/v9"
10+
)
11+
12+
type SlidingWindow struct {
13+
client *redis.Client
14+
window time.Duration
15+
limit int
16+
mu sync.Mutex
17+
}
18+
19+
func NewSlidingWindow(client *redis.Client, window time.Duration, limit int) *SlidingWindow {
20+
return &SlidingWindow{
21+
client: client,
22+
window: window,
23+
limit: limit,
24+
}
25+
}
26+
27+
func (sw *SlidingWindow) Allow(ctx context.Context, key string) (bool, error) {
28+
sw.mu.Lock()
29+
defer sw.mu.Unlock()
30+
31+
now := time.Now().UnixMilli()
32+
redisKey := fmt.Sprintf("sw:%s", key)
33+
34+
windowStart := now - sw.window.Milliseconds()
35+
36+
pipe := sw.client.TxPipeline()
37+
38+
pipe.ZRemRangeByScore(ctx, redisKey, "0", fmt.Sprintf("%d", windowStart))
39+
40+
countCmd := pipe.ZCard(ctx, redisKey)
41+
42+
pipe.ZAdd(ctx, redisKey, redis.Z{Score: float64(now), Member: now})
43+
44+
pipe.Expire(ctx, redisKey, sw.window)
45+
46+
_, err := pipe.Exec(ctx)
47+
if err != nil {
48+
return false, err
49+
}
50+
51+
if countCmd.Val() >= int64(sw.limit) {
52+
return false, nil
53+
}
54+
55+
return true, nil
56+
}

0 commit comments

Comments
 (0)