代码之家  ›  专栏  ›  技术社区  ›  Shiva

lua脚本/redis中的打印方法不起作用

  •  0
  • Shiva  · 技术社区  · 2 年前

    我正在尝试执行以下脚本,并得到以下错误。 Redis正在docker中运行

    线程“main”org.respon.client.RedisException异常:ERR user_script:1:脚本试图访问不存在的全局变量 “打印”脚本:6f736423f082e141036b833d1f86b5a36a494611,位于 @user_script:1。。

    使用redis CLI执行时也会出现相同的错误

    127.0.0.1:6379>eval“print(”Comparison is_made b/w minimum_value of two is:“)”0(错误)ERR user_script:1:脚本尝试 访问不存在的全局变量“print”脚本: 8598b7f0db450c711d3a9e73a296e331bd1ef945,在@user_script:1上。 127.0.0.1:6379>

    Java代码。我正在使用Redison lib连接到Redis并执行脚本。

     String script = "local rate = redis.call('hget', KEYS[1], 'rate');"
                    + "local interval = redis.call('hget', KEYS[1], 'interval');"
                    + "local type = redis.call('hget', KEYS[1], 'type');"
                    + "assert(rate ~= false and interval ~= false and type ~= false, 'RateLimiter is not initialized')"
    
                    + "local valueName = KEYS[2];"
                    + "local permitsName = KEYS[4];"
                    + "if type == '1' then "
                    + "valueName = KEYS[3];"
                    + "permitsName = KEYS[5];"
                    + "end;"
                    +"print(\"rate\"..rate) ;"
                    +"print(\"interval\"..interval) ;"
                    +"print(\"type\"..type); "
                    + "assert(tonumber(rate) >= tonumber(ARGV[1]), 'Requested permits amount could not exceed defined rate'); "
    
                    + "local currentValue = redis.call('get', valueName); "
                    + "local res;"
                    + "if currentValue ~= false then "
                    + "local expiredValues = redis.call('zrangebyscore', permitsName, 0, tonumber(ARGV[2]) - interval); "
                    + "local released = 0; "
                    + "for i, v in ipairs(expiredValues) do "
                    + "local random, permits = struct.unpack('Bc0I', v);"
                    + "released = released + permits;"
                    + "end; "
    
                    + "if released > 0 then "
                    + "redis.call('zremrangebyscore', permitsName, 0, tonumber(ARGV[2]) - interval); "
                    + "if tonumber(currentValue) + released > tonumber(rate) then "
                    + "currentValue = tonumber(rate) - redis.call('zcard', permitsName); "
                    + "else "
                    + "currentValue = tonumber(currentValue) + released; "
                    + "end; "
                    + "redis.call('set', valueName, currentValue);"
                    + "end;"
    
                    + "if tonumber(currentValue) < tonumber(ARGV[1]) then "
                    + "local firstValue = redis.call('zrange', permitsName, 0, 0, 'withscores'); "
                    + "res = 3 + interval - (tonumber(ARGV[2]) - tonumber(firstValue[2]));"
                    + "else "
                    + "redis.call('zadd', permitsName, ARGV[2], struct.pack('Bc0I', string.len(ARGV[3]), ARGV[3], ARGV[1])); "
                    + "redis.call('decrby', valueName, ARGV[1]); "
                    + "res = nil; "
                    + "end; "
                    + "else "
                    + "redis.call('set', valueName, rate); "
                    + "redis.call('zadd', permitsName, ARGV[2], struct.pack('Bc0I', string.len(ARGV[3]), ARGV[3], ARGV[1])); "
                    + "redis.call('decrby', valueName, ARGV[1]); "
                    + "res = nil; "
                    + "end;"
    
                    + "local ttl = redis.call('pttl', KEYS[1]); "
                    + "if ttl > 0 then "
                    + "redis.call('pexpire', valueName, ttl); "
                    + "redis.call('pexpire', permitsName, ttl); "
                    + "end; "
                    + "return res;";
    
            RedissonClient client = null;
            try {
                 client = Redisson.create();
                client.getRateLimiter("user1:endpoint1").setRate(
                        RateType.PER_CLIENT, 5, 1, RateIntervalUnit.SECONDS);
                String sha1 = client.getScript().scriptLoad(script);
                List<Object> keys =
                        Arrays.asList("user1:endpoint1", "{user1:endpoint1}:value",
                                "{user1:endpoint1}:value:febbb04d-6365-4cb8-b32b-8d90800cd4e6",
                                "{user1:endpoint1}:permits", "{user1:endpoint1}:permits:febbb04d-6365-4cb8-b32b-8d90800cd4e6");
                byte[] random = new byte[8];
                ThreadLocalRandom.current().nextBytes(random);
                Object args[] = {1, System.currentTimeMillis(), random};
                boolean res = client.getScript().evalSha(READ_WRITE, sha1, RScript.ReturnType.BOOLEAN, keys, 1,
                        System.currentTimeMillis(), random);
    
                System.out.println(res);
            }finally {
                if(client != null && !client.isShutdown()){
                    client.shutdown();
                }
            }
    

    检查了 Lua print on the same line 线程但是 io.write 也给出了相同的错误。

    0 回复  |  直到 2 年前
        1
  •  1
  •   koyaanisqatsi    2 年前

    正如评论中所写 return() 似乎是唯一的办法。
    redis cli的示例(设置redis DB并在Lua中使用它)
    (收集数据并作为一个字符串返回)

    set LuaV 'local txt = "" for k, v in pairs(redis) do txt = txt .. tostring(k) .. " => " .. tostring(v) .. " | " end return(txt)'
    

    现在 eval

    eval "local f = redis.call('GET', KEYS[1]) return(loadstring(f))()" 1 LuaV
    

    …显示表中的内容: redis
    (一个长字符串不可能)

    • 异常: eval 'redis.log(2, _VERSION)' 0 在不结束脚本的情况下发出,但仅在服务器上发出。
      \n 当你这样做的时候。。。
    set LuaV 'local txt = "" for k, v in pairs(redis) do txt = txt .. tostring(k) .. " => " .. tostring(v) .. "\n" end return(txt)' 
    

    …和 eval

    eval 'local f = redis.call("GET", KEYS[1]) f = loadstring(f)() redis.log(2, f)' 1 LuaV