Re: [I] bug: limit-req: conf_type/conf_version suffix makes per-consumer rate limits effectively per-route [apisix]
Baoyuantop commented on issue #12946:
URL: https://github.com/apache/apisix/issues/12946#issuecomment-3949354952
Hi @janiussyafiq, Thank you for reminding me, I have verified that this is
indeed the case.
The following test cases can be executed successfully.
```
=== TEST 1: setup consumer with limit-count and two routes (no limit-count
on routes)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
t('/apisix/admin/consumers', ngx.HTTP_PUT, [[{
"username": "jack",
"plugins": {
"key-auth": { "key": "auth-key" },
"limit-count": {
"count": 1,
"time_window": 60,
"rejected_code": 429,
"key": "consumer_name"
}
}
}]])
-- route A
t('/apisix/admin/routes/1', ngx.HTTP_PUT, [[{
"uri": "/hello", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
-- route B
t('/apisix/admin/routes/2', ngx.HTTP_PUT, [[{
"uri": "/hello1", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
=== TEST 2: cross-route requests - limit-count on consumer should be shared
globally
--- pipelined_requests eval
["GET /hello", "GET /hello1"]
--- more_headers
apikey: auth-key
--- error_code eval
[200, 429]
```
```
=== TEST 1: setup consumer with limit-req and two routes (no limit-req on
routes)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
t('/apisix/admin/consumers', ngx.HTTP_PUT, [[{
"username": "jack",
"plugins": {
"key-auth": { "key": "auth-key" },
"limit-req": {
"rate": 0.1,
"burst": 0,
"rejected_code": 403,
"key": "consumer_name"
}
}
}]])
-- route A
t('/apisix/admin/routes/1', ngx.HTTP_PUT, [[{
"uri": "/hello", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
-- route B
t('/apisix/admin/routes/2', ngx.HTTP_PUT, [[{
"uri": "/hello1", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
=== TEST 2: cross-route requests - limit-req on consumer should be shared
globally
--- pipelined_requests eval
["GET /hello", "GET /hello1"]
--- more_headers
apikey: auth-key
--- error_code eval
[200, 200]
```
The limit-req and limit-count plugins exhibit inconsistent behavior; their
key concatenation methods differ.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [I] bug: limit-req: conf_type/conf_version suffix makes per-consumer rate limits effectively per-route [apisix]
janiussyafiq commented on issue #12946: URL: https://github.com/apache/apisix/issues/12946#issuecomment-3932007641 Hi @Baoyuantop, just to let u know that the test u provided will also pass without the `group` config within `limit-count` plugin. I verified it by manual testing. Initially, my fix would be adding group config to `limit-req` plugin but since this behavior wouldn't require the group config to work, I'll implement the simpler fix w/o adding group config. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [I] bug: limit-req: conf_type/conf_version suffix makes per-consumer rate limits effectively per-route [apisix]
falvaradorodriguez commented on issue #12946: URL: https://github.com/apache/apisix/issues/12946#issuecomment-3816302646 Hello @Baoyuantop, Thank you very much for your explanation. Sorry for indicate it as a bug. In my specific case, what you mention is a limitation, and it would be very helpful to add the `group` parameter to this plugin as well. My scenario is as follows. Each consumer has its own RPS configuration and monthly request quota. To achieve this, I need to configure the limit-req and limit-count plugins together. This limits me to using the limit-count plugin for RPS, as it is the only way I know to manage the monthly quota. The RPS configuration is common to the consumer, so if the `limit-req` plugin groups by route, my scenario is not possible. I look forward to seeing if it is possible to add this feature to the project. Thanks a lot in advance. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [I] bug: limit-req: conf_type/conf_version suffix makes per-consumer rate limits effectively per-route [apisix]
Baoyuantop commented on issue #12946:
URL: https://github.com/apache/apisix/issues/12946#issuecomment-3815756300
Hi @falvaradorodriguez, I have confirmed that this is expected behavior, not
a bug.
By default, each route in APISIX has its own separate rate-limiting counter.
We later introduced the `group` configuration option in the `limit-count`
plugin to achieve the scenario you described. However, this configuration
option has not yet been added to other rate-limiting plugins.
The following test cases have been verified to pass.
```
=== TEST 1: setup consumer with group and routes
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- consumer with limit-count: count=1, time_window=60,
group="jack-limit"
t('/apisix/admin/consumers', ngx.HTTP_PUT, [[{
"username": "jack",
"plugins": {
"key-auth": { "key": "auth-key" },
"limit-count": {
"count": 1,
"time_window": 60,
"rejected_code": 429,
"key": "consumer_name",
"group": "jack-limit"
}
}
}]])
-- route A
t('/apisix/admin/routes/1', ngx.HTTP_PUT, [[{
"uri": "/hello", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
-- route B
t('/apisix/admin/routes/2', ngx.HTTP_PUT, [[{
"uri": "/hello1", "plugins": { "key-auth": {} },
"upstream": { "nodes": { "127.0.0.1:1980": 1 }, "type":
"roundrobin" }
}]])
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
=== TEST 2: cross-route requests - with group, counter is shared globally
Consumer has count=1 with group="jack-limit", requests across routes share
the same counter.
EXPECTED: [200, 429]
--- pipelined_requests eval
["GET /hello", "GET /hello1"]
--- more_headers
apikey: auth-key
--- error_code eval
[200, 429]
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
[I] bug: limit-req: conf_type/conf_version suffix makes per-consumer rate limits effectively per-route [apisix]
falvaradorodriguez opened a new issue, #12946:
URL: https://github.com/apache/apisix/issues/12946
### Current Behavior
When the limit-req plugin is configured only at the Consumer level, the
effective rate limit is still scoped per route, not per consumer.
Internally, limit-req always appends ctx.conf_type and ctx.conf_version to
the generated key. At runtime, ctx.conf_type includes both route and consumer
(e.g. route&consumer), and conf_version includes the route ID. As a result, a
separate Redis counter is created for each route, even though the plugin is not
configured on the routes themselves.
This can be observed in logs such as:
```
conf type: route&consumer
conf version: &
limit key: route&consumer
```
Because of this behavior, a consumer configured with N req/sec can
effectively make N req/sec per route, which bypasses the expected global
per-consumer rate limit.
There is currently no configuration option in limit-req to prevent the
conf_type/conf_version suffix from being added, making it impossible to
implement a true global per-consumer leaky-bucket rate limit using limit-req.
### Expected Behavior
When the limit-req plugin is configured at the Consumer level, the rate
limit should apply globally to that consumer, regardless of which route is
being accessed.
In this scenario, all requests made by the same consumer should share a
single rate-limit bucket, so that a consumer configured with N req/sec can only
make N req/sec in total, even when calling multiple routes.
More generally, users should be able to control the scope of the rate-limit
key (for example, per route vs. per consumer), or at least have a way to
prevent route-specific information from being implicitly included in the
rate-limit key when the plugin is defined on a consumer.
This would allow limit-req to be used for true global per-consumer rate
limiting, without requiring custom plugin overrides or switching to a different
rate-limiting plugin.
### Error Logs
The following logs were captured by adding debug prints in limit-req.lua
while sending requests from the same consumer to different routes.
```
key = key .. ctx.conf_type .. ctx.conf_version
core.log.error("limit key: ", key)
core.log.error("conf type: ", ctx.conf_type)
core.log.error("conf version: ", ctx.conf_version)
```
Even though limit-req is configured only on the Consumer, the plugin reports
a combined configuration context (route&consumer), and the generated key
includes route-specific information:
```
2026/01/27 13:11:59 [error] 204#204: *53475 [lua] limit-req.lua:162:
phase_func(): conf version: 2008&1, client: 192.168.65.1, server: _, request:
"GET /test HTTP/1.1", host: "localhost:9080"
2026/01/27 13:12:00 [error] 194#194: *53481 [lua] limit-req.lua:160:
phase_func(): limit key: 192.168.65.1route&consumer2008&1, client:
192.168.65.1, server: _, request: "GET /test HTTP/1.1", host: "localhost:9080"
2026/01/27 13:12:00 [error] 194#194: *53481 [lua] limit-req.lua:161:
phase_func(): conf type: route&consumer, client: 192.168.65.1, server: _,
request: "GET /test HTTP/1.1", host: "localhost:9080"
```
These logs show that the rate-limit key is effectively namespaced by both
the route and the consumer, resulting in separate rate-limit counters per route.
### Steps to Reproduce
1. Start APISIX 3.12 and Redis
Run APISIX 3.12 with Redis enabled (local or via Docker).
Ensure Redis is reachable from APISIX.
2. Create a Consumer with key-auth and limit-req
Configure limit-req only at the Consumer level:
```
curl -X PUT http://127.0.0.1:9180/apisix/admin/consumers/test-consumer \
-H 'X-API-KEY: ' \
-H 'Content-Type: application/json' \
-d '{
"username": "test-consumer",
"plugins": {
"key-auth": {
"key": "test-api-key"
},
"limit-req": {
"rate": 2,
"burst": 0,
"key": "consumer_name",
"key_type": "var",
"policy": "redis",
"redis_host": "redis",
"redis_port": 6379,
"redis_database": 0
}
}
}'
```
3. Create two routes using key-auth
Route A:
```
curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: ' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/route-a",
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
Route B:
```
curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/2 \
-H 'X-API-KEY: ' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/route-b",
"plugins": {
"key-au
