membphis commented on code in PR #12872:
URL: https://github.com/apache/apisix/pull/12872#discussion_r2715579601


##########
apisix/plugins/limit-conn/util.lua:
##########
@@ -18,36 +18,66 @@
 local assert            = assert
 local math              = require "math"
 local floor             = math.floor
+local ngx               = ngx
+local ngx_time          = ngx.time
+local uuid              = require("resty.jit-uuid")
+
 local _M = {version = 0.3}
+local redis_incoming_script = [[
+    local key = KEYS[1]
+    local limit = tonumber(ARGV[1])
+    local ttl = tonumber(ARGV[2])
+    local now = tonumber(ARGV[3])
+    local req_id = ARGV[4]
+
+    redis.call('ZREMRANGEBYSCORE', key, 0, now)
+
+    local count = redis.call('ZCARD', key)
+    if count >= limit then
+        return {0, count}
+    end
+
+    redis.call('ZADD', key, now + ttl, req_id)
+    redis.call('EXPIRE', key, ttl)
+    return {1, count + 1}
+]]
 
 
 function _M.incoming(self, red, key, commit)
     local max = self.max
     self.committed = false
+    local raw_key = key
     key = "limit_conn" .. ":" .. key
 
-    local conn, err
+    local conn
     if commit then
-        conn, err = red:incrby(key, 1)
-        if not conn then
+        local req_id = ngx.ctx.request_id or uuid.generate_v4()
+        if not ngx.ctx.limit_conn_req_ids then
+            ngx.ctx.limit_conn_req_ids = {}
+        end
+        ngx.ctx.limit_conn_req_ids[raw_key] = req_id
+
+        local now = ngx_time()
+        local res, err = red:eval(redis_incoming_script, 1, key,

Review Comment:
   you can take a look at this example, which is better performance
   
   we can cache the `sha1` of Lua script, then we call `evalsha`
   
   ```lua
   local redis = require "resty.redis"
   local red = redis:new()
   
   -- 1. Define your fixed script and pre-calculate its SHA1 locally
   -- You can use an online SHA1 tool or calculate it via code
   local script_content = "return redis.call('GET', KEYS[1])"
   local script_sha1 = "6bce267422d7793d3e0034d7c99602029c5737e6"
   
   red:set_timeout(1000) -- 1 sec
   local ok, err = red:connect("127.0.0.1", 6379)
   if not ok then
       ngx.log(ngx.ERR, "failed to connect: ", err)
       return
   end
   
   --- Function to execute script with EVALSHA optimization
   local function optimized_eval(red, sha1, script, num_keys, ...)
       -- Try EVALSHA first
       local res, err = red:evalsha(sha1, num_keys, ...)
       
       -- If the script is missing in Redis (NOSCRIPT error)
       if not res and err and string.find(err, "NOSCRIPT") then
           ngx.log(ngx.INFO, "Script not found in cache, loading now...")
           
           -- Load the script to get the SHA1 (or verify it)
           local new_sha, load_err = red:script("LOAD", script)
           if not new_sha then
               return nil, "failed to load script: " .. (load_err or "")
           end
           
           -- Retry EVALSHA with the loaded script
           return red:evalsha(new_sha, num_keys, ...)
       end
       
       return res, err
   end
   
   -- 2. Call the function
   local res, err = optimized_eval(red, script_sha1, script_content, 1, 
"my_key")
   
   if not res then
       ngx.say("Error: ", err)
   else
       ngx.say("Result: ", res)
   end
   
   -- Put it back in the connection pool
   red:set_keepalive(10000, 100)



-- 
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]

Reply via email to