Skip to content

Conversation

@beardnick
Copy link
Contributor

@beardnick beardnick commented Nov 16, 2025

Description

Which issue(s) this PR fixes:

Fixes #12482

Notice
  • I have updated the limit-count-redis.lua and limit-count-redis-cluster.lua files to ensure they now support rate-limiting during the log phase.
  • I referred to the limit-conn-redis.lua file as a guide while implementing rate-limiting in the log phase.
  • To ensure a clean testing environment, I added the require("lib.test_redis").flush_all() function to every Redis rate-limiting test case. Without this addition, the tests could fail unpredictably.
  • I have adjusted the expected results in limit-req-redis.t and limit-req-redis-cluster.t test cases. After thorough verification, the correct behavior is [200, 403, 403, 403]. Previously, the results appeared as [403, 403, 403, 403] due to Redis not being properly cleaned beforehand.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Nov 16, 2025
@beardnick beardnick changed the title Feature/ai rate limiting redis support feat: ai rate limiting redis support Nov 16, 2025
@beardnick
Copy link
Contributor Author

@Baoyuantop PTAL

@membphis
Copy link
Member

@beardnick many thx for your contribution, some CI tests are failed, you can fix them

@@ -0,0 +1,85 @@
--
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apisix/plugins/limit-count/util.lua

I checked _M.incoming and _M.log_phase_incoming, and they both work for redis.

We should add redis to the filename of the function name.

local phase = get_phase()
if phase == "log" then
if not conf.policy or conf.policy == "local" then
lim:incoming(key, not dry_run, conf, cost)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional statement is unnecessary, as an identical check is performed again a few lines later:

local delay, remaining, reset
    if not conf.policy or conf.policy == "local" then
        delay, remaining, reset = lim:incoming(key, not dry_run, conf, cost)
    else
        delay, remaining, reset = lim:incoming(key, cost, dry_run)
    end

And why do we need to perform two incoming operations during the log phase?

Comment on lines +32 to +45
local peek_script = core.string.compress_script([=[
local ttl = redis.call('ttl', KEYS[1])
local limit = tonumber(ARGV[1])
local cost = tonumber(ARGV[3])
if ttl < 0 then
return {limit - cost, tonumber(ARGV[2])}
end
local current = redis.call('get', KEYS[1])
if not current then
return {limit - cost, tonumber(ARGV[2])}
end
return {tonumber(current) - cost, ttl}
]=])

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to use a separate Redis script? Can we just remove

assert(tonumber(ARGV[3]) >= 1, "cost must be at least 1")

from the commit_script directly?

location /test_concurrency {
content_by_lua_block {
require("lib.test_redis").flush_all()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were we able to pass the tests without this flush before?

Copy link
Member

@nic-6443 nic-6443 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look like the changes in this PR should be limited to the ai-rate-limiting plugin and minor tweaks to the limit-count plugin. The current PR modifies too much code and test cases for other rate limiting plugins, expanding its scope. We should minimize unnecessary code changes.

Comment on lines +51 to +56
local commit = true
if dry_run ~= nil then
commit = not dry_run
end

local ttl = 0
local res, err = red:eval(script, 1, key, limit, window, cost or 1)
return util.redis_incoming(self, self.red_cli, key, commit, cost)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we directly check ngx.phase here? This way, the APIs of limit-count-redis-cluster.lua and limit-count-redis.lua do not need to be changed, still only providing an incoming function without introducing a new log_phase_incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

help request: How to config ai-rate-limiting plugin's counter to redis, as limit-count plugin

4 participants