Skip to content

Commit 4bc4e2c

Browse files
fix(limit-req): ensure safe eviction of keys in redis (apache#12911)
1 parent 9718c69 commit 4bc4e2c

File tree

5 files changed

+137
-24
lines changed

5 files changed

+137
-24
lines changed

apisix/plugins/limit-req/util.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ function _M.incoming(self, red, key, commit)
5757
end
5858

5959
if commit then
60-
local ok
61-
local err
62-
ok, err = red:set(excess_key, excess)
60+
local ttl = math.ceil(self.burst / self.rate) + 1
61+
local ok, err
62+
63+
ok, err = red:set(excess_key, excess, "EX", ttl)
6364
if not ok then
6465
return nil, err
6566
end
6667

67-
ok, err = red:set(last_key, now)
68+
ok, err = red:set(last_key, now, "EX", ttl)
6869
if not ok then
6970
return nil, err
7071
end

ci/common.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ GRPC_SERVER_EXAMPLE_VER=20210819
177177

178178
linux_get_dependencies () {
179179
apt update
180-
apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl libpcre3 libpcre3-dev libpcre2-dev xz-utils
180+
apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl libpcre3 libpcre3-dev libpcre2-dev xz-utils redis-tools
181181
apt remove -y curl
182182
apt-get install -y libyaml-dev
183183
wget https://github.com/mikefarah/yq/releases/download/3.4.1/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq

ci/pod/docker-compose.common.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@
1818
version: "3.8"
1919

2020
services:
21+
## Redis
22+
apisix_redis:
23+
# The latest image is the latest stable version
24+
image: redis:latest
25+
restart: unless-stopped
26+
volumes:
27+
- ./t/certs:/certs
28+
command: "--tls-port 6380 \
29+
--tls-cert-file /certs/mtls_server.crt \
30+
--tls-key-file /certs/mtls_server.key \
31+
--tls-ca-cert-file /certs/mtls_ca.crt \
32+
--tls-auth-clients no \
33+
--user alice on +@all ~* \\&* \\>somepassword"
34+
ports:
35+
- "6379:6379"
36+
- "6380:6380"
37+
2138
## Etcd
2239
etcd_old:
2340
image: bitnamilegacy/etcd:3.3.8

ci/pod/docker-compose.plugin.yml

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,6 @@
1818
version: "3.8"
1919

2020
services:
21-
## Redis
22-
apisix_redis:
23-
# The latest image is the latest stable version
24-
image: redis:latest
25-
restart: unless-stopped
26-
volumes:
27-
- ./t/certs:/certs
28-
command: "--tls-port 6380 \
29-
--tls-cert-file /certs/mtls_server.crt \
30-
--tls-key-file /certs/mtls_server.key \
31-
--tls-ca-cert-file /certs/mtls_ca.crt \
32-
--tls-auth-clients no \
33-
--user alice on +@all ~* \\&* \\>somepassword"
34-
ports:
35-
- "6379:6379"
36-
- "6380:6380"
37-
networks:
38-
apisix_net:
39-
4021
## keycloak
4122
apisix_keycloak:
4223
container_name: apisix_keycloak

t/cli/test_limit_req_redis_ttl.sh

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership.
7+
# The ASF licenses this file to You under the Apache License, Version 2.0
8+
# (the "License"); you may not use this file except in compliance with
9+
# the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
#
19+
20+
. ./t/cli/common.sh
21+
22+
# Enable limit-req plugin
23+
24+
rm logs/worker_events.sock || true
25+
26+
echo '
27+
nginx_config:
28+
worker_processes: 1
29+
error_log_level: info
30+
deployment:
31+
admin:
32+
admin_key:
33+
- name: "admin"
34+
key: edd1c9f034335f136f87ad84b625c8f1
35+
role: admin
36+
37+
apisix:
38+
enable_admin: true
39+
control:
40+
port: 9110
41+
plugins:
42+
- limit-req
43+
' > conf/config.yaml
44+
45+
make init
46+
make run
47+
48+
admin_key="edd1c9f034335f136f87ad84b625c8f1"
49+
50+
# Create a route with limit-req and redis policy
51+
# rate=1, burst=1 -> ttl = ceil(1/1) + 1 = 2s
52+
curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/1 \
53+
-H "X-API-KEY: $admin_key" \
54+
-d '{
55+
"methods": ["GET"],
56+
"uri": "/hello",
57+
"plugins": {
58+
"limit-req": {
59+
"rate": 1,
60+
"burst": 1,
61+
"key": "remote_addr",
62+
"policy": "redis",
63+
"redis_host": "127.0.0.1",
64+
"redis_timeout": 1000
65+
}
66+
},
67+
"upstream": {
68+
"type": "roundrobin",
69+
"nodes": {
70+
"127.0.0.1:1980": 1
71+
}
72+
}
73+
}'
74+
75+
if [ $? -ne 0 ]; then
76+
echo "failed: verify route creation"
77+
exit 1
78+
fi
79+
80+
sleep 0.5
81+
82+
# Make a request to create the Redis keys
83+
curl -v http://127.0.0.1:9080/hello > /dev/null 2>&1
84+
85+
# Verify keys exist
86+
# Keys pattern: plugin-limit-req*
87+
keys=$(redis-cli keys "limit_req:*" | wc -l)
88+
if [ "$keys" -eq 0 ]; then
89+
echo "failed: keys not found in Redis immediately after request"
90+
exit 1
91+
fi
92+
echo "pass: keys found in Redis"
93+
94+
# Wait for 3 seconds (TTL is 2s)
95+
echo "Waiting for 3s..."
96+
sleep 3
97+
98+
# Verify keys are gone
99+
keys_list=$(redis-cli keys "limit_req:*")
100+
101+
if [ -n "$keys_list" ]; then
102+
echo "failed: keys still exist in Redis after TTL expiration"
103+
echo "Keys found:"
104+
echo "$keys_list"
105+
106+
first_key=$(echo "$keys_list" | head -n 1)
107+
echo "TTL of $first_key:"
108+
redis-cli ttl "$first_key"
109+
110+
exit 1
111+
fi
112+
113+
echo "pass: keys expired correctly"
114+
make stop

0 commit comments

Comments
 (0)