File tree Expand file tree Collapse file tree 5 files changed +38
-7
lines changed Expand file tree Collapse file tree 5 files changed +38
-7
lines changed Original file line number Diff line number Diff line change @@ -262,7 +262,8 @@ max_concurrent_queries: <int> | optional | default = 0
262
262
max_execution_time : <duration> | optional | default = 120s
263
263
264
264
# Maximum number of requests per minute for user.
265
- # By default there are no per-minute limits
265
+ # By default there are no per-minute limits.
266
+ # A negative value would effectively block the user.
266
267
requests_per_minute : <int> | optional | default = 0
267
268
268
269
# The burst of request packet size token bucket for user
Original file line number Diff line number Diff line change @@ -733,7 +733,8 @@ type User struct {
733
733
734
734
// Maximum number of requests per minute for user
735
735
// if omitted or zero - no limits would be applied
736
- ReqPerMin uint32 `yaml:"requests_per_minute,omitempty"`
736
+ // if negative - the user is effectively blocked
737
+ ReqPerMin int32 `yaml:"requests_per_minute,omitempty"`
737
738
738
739
// The burst of request packet size token bucket for user
739
740
// if omitted or zero - no limits would be applied
@@ -1086,7 +1087,8 @@ type ClusterUser struct {
1086
1087
1087
1088
// Maximum number of requests per minute for user
1088
1089
// if omitted or zero - no limits would be applied
1089
- ReqPerMin uint32 `yaml:"requests_per_minute,omitempty"`
1090
+ // if negative - the user is effectively blocked
1091
+ ReqPerMin int32 `yaml:"requests_per_minute,omitempty"`
1090
1092
1091
1093
// The burst of request packet size token bucket for user
1092
1094
// if omitted or zero - no limits would be applied
Original file line number Diff line number Diff line change @@ -33,6 +33,12 @@ users:
33
33
max_queue_time : 25s
34
34
cache : " shortterm"
35
35
36
+ - name : " blocked"
37
+ password : " ****"
38
+ to_cluster : " stats-raw"
39
+ to_user : " blocked"
40
+ requests_per_minute : -1
41
+
36
42
clusters :
37
43
- name : " stats-aggregate"
38
44
nodes : [
Original file line number Diff line number Diff line change @@ -415,6 +415,17 @@ func TestReverseProxy_ServeHTTP1(t *testing.T) {
415
415
return makeRequest (p )
416
416
},
417
417
},
418
+ {
419
+ cfg : goodCfg ,
420
+ name : "max requests per minute negative for cluster user" ,
421
+ expResponse : "rate limit for cluster user \" web\" is exceeded: requests_per_minute limit: -1" ,
422
+ expStatusCode : http .StatusTooManyRequests ,
423
+ f : func (p * reverseProxy ) * http.Response {
424
+ p .clusters ["cluster" ].users ["web" ].reqPerMin = - 1
425
+ runHeavyRequestInGoroutine (p , 1 , true )
426
+ return makeRequest (p )
427
+ },
428
+ },
418
429
{
419
430
cfg : goodCfg ,
420
431
name : "max time for cluster user" ,
@@ -458,6 +469,17 @@ func TestReverseProxy_ServeHTTP1(t *testing.T) {
458
469
return makeRequest (p )
459
470
},
460
471
},
472
+ {
473
+ cfg : goodCfg ,
474
+ name : "max requests per minute negative for user" ,
475
+ expResponse : fmt .Sprintf ("rate limit for user %q is exceeded: requests_per_minute limit: -1" , defaultUsername ),
476
+ expStatusCode : http .StatusTooManyRequests ,
477
+ f : func (p * reverseProxy ) * http.Response {
478
+ p .users [defaultUsername ].reqPerMin = - 1
479
+ runHeavyRequestInGoroutine (p , 1 , true )
480
+ return makeRequest (p )
481
+ },
482
+ },
461
483
{
462
484
cfg : goodCfg ,
463
485
name : "queuing queries for user" ,
Original file line number Diff line number Diff line change @@ -255,11 +255,11 @@ func (s *scope) checkTokenFreeRateLimiters() error {
255
255
// is decremented on error below after per-minute zeroing
256
256
// in rateLimiter.run.
257
257
// These races become innocent with the given check.
258
- if s .user .reqPerMin > 0 && int32 (uRPM ) > 0 && uRPM > s .user .reqPerMin {
258
+ if ( s .user .reqPerMin > 0 && int32 (uRPM ) > 0 && uRPM > uint32 ( s .user .reqPerMin )) || s . user . reqPerMin < 0 {
259
259
err = fmt .Errorf ("rate limit for user %q is exceeded: requests_per_minute limit: %d" ,
260
260
s .user .name , s .user .reqPerMin )
261
261
}
262
- if s .clusterUser .reqPerMin > 0 && int32 (cRPM ) > 0 && cRPM > s .clusterUser .reqPerMin {
262
+ if ( s .clusterUser .reqPerMin > 0 && int32 (cRPM ) > 0 && cRPM > uint32 ( s .clusterUser .reqPerMin )) || s . clusterUser . reqPerMin < 0 {
263
263
err = fmt .Errorf ("rate limit for cluster user %q is exceeded: requests_per_minute limit: %d" ,
264
264
s .clusterUser .name , s .clusterUser .reqPerMin )
265
265
}
@@ -525,7 +525,7 @@ type user struct {
525
525
526
526
maxExecutionTime time.Duration
527
527
528
- reqPerMin uint32
528
+ reqPerMin int32
529
529
rateLimiter rateLimiter
530
530
531
531
reqPacketSizeTokenLimiter * rate.Limiter
@@ -635,7 +635,7 @@ type clusterUser struct {
635
635
636
636
maxExecutionTime time.Duration
637
637
638
- reqPerMin uint32
638
+ reqPerMin int32
639
639
rateLimiter rateLimiter
640
640
641
641
queueCh chan struct {}
You can’t perform that action at this time.
0 commit comments