This is an automated email from the ASF dual-hosted git repository.
baoyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 4bc4e2c04 fix(limit-req): ensure safe eviction of keys in redis
(#12911)
4bc4e2c04 is described below
commit 4bc4e2c0486296029a1e78ed816e033cc253d6c2
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Mon Jan 19 11:30:07 2026 +0545
fix(limit-req): ensure safe eviction of keys in redis (#12911)
---
apisix/plugins/limit-req/util.lua | 9 +--
ci/common.sh | 2 +-
ci/pod/docker-compose.common.yml | 17 ++++++
ci/pod/docker-compose.plugin.yml | 19 -------
t/cli/test_limit_req_redis_ttl.sh | 114 ++++++++++++++++++++++++++++++++++++++
5 files changed, 137 insertions(+), 24 deletions(-)
diff --git a/apisix/plugins/limit-req/util.lua
b/apisix/plugins/limit-req/util.lua
index 282c04cf9..6724889f1 100644
--- a/apisix/plugins/limit-req/util.lua
+++ b/apisix/plugins/limit-req/util.lua
@@ -57,14 +57,15 @@ function _M.incoming(self, red, key, commit)
end
if commit then
- local ok
- local err
- ok, err = red:set(excess_key, excess)
+ local ttl = math.ceil(self.burst / self.rate) + 1
+ local ok, err
+
+ ok, err = red:set(excess_key, excess, "EX", ttl)
if not ok then
return nil, err
end
- ok, err = red:set(last_key, now)
+ ok, err = red:set(last_key, now, "EX", ttl)
if not ok then
return nil, err
end
diff --git a/ci/common.sh b/ci/common.sh
index 67daf0115..b99819b5e 100644
--- a/ci/common.sh
+++ b/ci/common.sh
@@ -177,7 +177,7 @@ GRPC_SERVER_EXAMPLE_VER=20210819
linux_get_dependencies () {
apt update
- apt install -y cpanminus build-essential libncurses5-dev libreadline-dev
libssl-dev perl libpcre3 libpcre3-dev libpcre2-dev xz-utils
+ apt install -y cpanminus build-essential libncurses5-dev libreadline-dev
libssl-dev perl libpcre3 libpcre3-dev libpcre2-dev xz-utils redis-tools
apt remove -y curl
apt-get install -y libyaml-dev
wget
https://github.com/mikefarah/yq/releases/download/3.4.1/yq_linux_amd64 -O
/usr/bin/yq && sudo chmod +x /usr/bin/yq
diff --git a/ci/pod/docker-compose.common.yml b/ci/pod/docker-compose.common.yml
index 8a62c2b96..756900b18 100644
--- a/ci/pod/docker-compose.common.yml
+++ b/ci/pod/docker-compose.common.yml
@@ -18,6 +18,23 @@
version: "3.8"
services:
+ ## Redis
+ apisix_redis:
+ # The latest image is the latest stable version
+ image: redis:latest
+ restart: unless-stopped
+ volumes:
+ - ./t/certs:/certs
+ command: "--tls-port 6380 \
+ --tls-cert-file /certs/mtls_server.crt \
+ --tls-key-file /certs/mtls_server.key \
+ --tls-ca-cert-file /certs/mtls_ca.crt \
+ --tls-auth-clients no \
+ --user alice on +@all ~* \\&* \\>somepassword"
+ ports:
+ - "6379:6379"
+ - "6380:6380"
+
## Etcd
etcd_old:
image: bitnamilegacy/etcd:3.3.8
diff --git a/ci/pod/docker-compose.plugin.yml b/ci/pod/docker-compose.plugin.yml
index 2c026b76a..a0923fd67 100644
--- a/ci/pod/docker-compose.plugin.yml
+++ b/ci/pod/docker-compose.plugin.yml
@@ -18,25 +18,6 @@
version: "3.8"
services:
- ## Redis
- apisix_redis:
- # The latest image is the latest stable version
- image: redis:latest
- restart: unless-stopped
- volumes:
- - ./t/certs:/certs
- command: "--tls-port 6380 \
- --tls-cert-file /certs/mtls_server.crt \
- --tls-key-file /certs/mtls_server.key \
- --tls-ca-cert-file /certs/mtls_ca.crt \
- --tls-auth-clients no \
- --user alice on +@all ~* \\&* \\>somepassword"
- ports:
- - "6379:6379"
- - "6380:6380"
- networks:
- apisix_net:
-
## keycloak
apisix_keycloak:
container_name: apisix_keycloak
diff --git a/t/cli/test_limit_req_redis_ttl.sh
b/t/cli/test_limit_req_redis_ttl.sh
new file mode 100755
index 000000000..61c92b5a0
--- /dev/null
+++ b/t/cli/test_limit_req_redis_ttl.sh
@@ -0,0 +1,114 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+. ./t/cli/common.sh
+
+# Enable limit-req plugin
+
+rm logs/worker_events.sock || true
+
+echo '
+nginx_config:
+ worker_processes: 1
+ error_log_level: info
+deployment:
+ admin:
+ admin_key:
+ - name: "admin"
+ key: edd1c9f034335f136f87ad84b625c8f1
+ role: admin
+
+apisix:
+ enable_admin: true
+ control:
+ port: 9110
+plugins:
+ - limit-req
+' > conf/config.yaml
+
+make init
+make run
+
+admin_key="edd1c9f034335f136f87ad84b625c8f1"
+
+# Create a route with limit-req and redis policy
+# rate=1, burst=1 -> ttl = ceil(1/1) + 1 = 2s
+curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/1 \
+ -H "X-API-KEY: $admin_key" \
+ -d '{
+ "methods": ["GET"],
+ "uri": "/hello",
+ "plugins": {
+ "limit-req": {
+ "rate": 1,
+ "burst": 1,
+ "key": "remote_addr",
+ "policy": "redis",
+ "redis_host": "127.0.0.1",
+ "redis_timeout": 1000
+ }
+ },
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ }
+}'
+
+if [ $? -ne 0 ]; then
+ echo "failed: verify route creation"
+ exit 1
+fi
+
+sleep 0.5
+
+# Make a request to create the Redis keys
+curl -v http://127.0.0.1:9080/hello > /dev/null 2>&1
+
+# Verify keys exist
+# Keys pattern: plugin-limit-req*
+keys=$(redis-cli keys "limit_req:*" | wc -l)
+if [ "$keys" -eq 0 ]; then
+ echo "failed: keys not found in Redis immediately after request"
+ exit 1
+fi
+echo "pass: keys found in Redis"
+
+# Wait for 3 seconds (TTL is 2s)
+echo "Waiting for 3s..."
+sleep 3
+
+# Verify keys are gone
+keys_list=$(redis-cli keys "limit_req:*")
+
+if [ -n "$keys_list" ]; then
+ echo "failed: keys still exist in Redis after TTL expiration"
+ echo "Keys found:"
+ echo "$keys_list"
+
+ first_key=$(echo "$keys_list" | head -n 1)
+ echo "TTL of $first_key:"
+ redis-cli ttl "$first_key"
+
+ exit 1
+fi
+
+echo "pass: keys expired correctly"
+make stop