@@ -13,6 +13,9 @@ internal class RedisFixedWindowManager
13
13
14
14
private static readonly LuaScript _redisScript = LuaScript . Prepare (
15
15
@"local expires_at = tonumber(redis.call(""get"", @expires_at_key))
16
+ local current = tonumber(redis.call(""get"", @rate_limit_key))
17
+ local requested = tonumber(@increment_amount)
18
+ local limit = tonumber(@permit_limit)
16
19
17
20
if not expires_at or expires_at < tonumber(@current_time) then
18
21
-- this is either a brand new window,
@@ -27,13 +30,19 @@ internal class RedisFixedWindowManager
27
30
redis.call(""expireat"", @expires_at_key, @next_expires_at + 1)
28
31
-- since the database was updated, return the new value
29
32
expires_at = @next_expires_at
33
+ current = 0
30
34
end
31
35
32
- -- now that the window either already exists or it was freshly initialized,
33
- -- increment the counter(`incrby` returns a number)
34
- local current = redis.call(""incrby"", @rate_limit_key, @increment_amount)
36
+ local allowed = current + requested <= limit
35
37
36
- return { current, expires_at }" ) ;
38
+ if allowed
39
+ then
40
+ -- now that the window either already exists or it was freshly initialized,
41
+ -- increment the counter(`incrby` returns a number)
42
+ current = redis.call(""incrby"", @rate_limit_key, @increment_amount)
43
+ end
44
+
45
+ return { current, expires_at, allowed }" ) ;
37
46
38
47
public RedisFixedWindowManager (
39
48
string partitionKey ,
@@ -46,7 +55,7 @@ public RedisFixedWindowManager(
46
55
RateLimitExpireKey = new RedisKey ( $ "rl:{{{partitionKey}}}:exp") ;
47
56
}
48
57
49
- internal async Task < RedisFixedWindowResponse > TryAcquireLeaseAsync ( )
58
+ internal async Task < RedisFixedWindowResponse > TryAcquireLeaseAsync ( int permitCount )
50
59
{
51
60
var now = DateTimeOffset . UtcNow ;
52
61
var nowUnixTimeSeconds = now . ToUnixTimeSeconds ( ) ;
@@ -59,9 +68,10 @@ internal async Task<RedisFixedWindowResponse> TryAcquireLeaseAsync()
59
68
{
60
69
rate_limit_key = RateLimitKey ,
61
70
expires_at_key = RateLimitExpireKey ,
71
+ permit_limit = _options . PermitLimit ,
62
72
next_expires_at = now . Add ( _options . Window ) . ToUnixTimeSeconds ( ) ,
63
73
current_time = nowUnixTimeSeconds ,
64
- increment_amount = 1D ,
74
+ increment_amount = permitCount ,
65
75
} ) ;
66
76
67
77
var result = new RedisFixedWindowResponse ( ) ;
@@ -70,13 +80,14 @@ internal async Task<RedisFixedWindowResponse> TryAcquireLeaseAsync()
70
80
{
71
81
result . Count = ( long ) response [ 0 ] ;
72
82
result . ExpiresAt = ( long ) response [ 1 ] ;
83
+ result . Allowed = ( bool ) response [ 2 ] ;
73
84
result . RetryAfter = TimeSpan . FromSeconds ( result . ExpiresAt - nowUnixTimeSeconds ) ;
74
85
}
75
86
76
87
return result ;
77
88
}
78
89
79
- internal RedisFixedWindowResponse TryAcquireLease ( )
90
+ internal RedisFixedWindowResponse TryAcquireLease ( int permitCount )
80
91
{
81
92
var now = DateTimeOffset . UtcNow ;
82
93
var nowUnixTimeSeconds = now . ToUnixTimeSeconds ( ) ;
@@ -89,9 +100,10 @@ internal RedisFixedWindowResponse TryAcquireLease()
89
100
{
90
101
rate_limit_key = RateLimitKey ,
91
102
expires_at_key = RateLimitExpireKey ,
103
+ permit_limit = _options . PermitLimit ,
92
104
next_expires_at = now . Add ( _options . Window ) . ToUnixTimeSeconds ( ) ,
93
105
current_time = nowUnixTimeSeconds ,
94
- increment_amount = 1D ,
106
+ increment_amount = permitCount ,
95
107
} ) ;
96
108
97
109
var result = new RedisFixedWindowResponse ( ) ;
@@ -100,6 +112,7 @@ internal RedisFixedWindowResponse TryAcquireLease()
100
112
{
101
113
result . Count = ( long ) response [ 0 ] ;
102
114
result . ExpiresAt = ( long ) response [ 1 ] ;
115
+ result . Allowed = ( bool ) response [ 2 ] ;
103
116
result . RetryAfter = TimeSpan . FromSeconds ( result . ExpiresAt - nowUnixTimeSeconds ) ;
104
117
}
105
118
@@ -112,5 +125,6 @@ internal class RedisFixedWindowResponse
112
125
internal long ExpiresAt { get ; set ; }
113
126
internal TimeSpan RetryAfter { get ; set ; }
114
127
internal long Count { get ; set ; }
128
+ internal bool Allowed { get ; set ; }
115
129
}
116
130
}
0 commit comments