Kadir Akin
Kadir Akin

Reputation: 101

Executing Lua Script with RedisTemplate never works

I am currently working on a benchmark tool for kafka and GC PubSub. I want to see results about min. max and avg transfer speed. In before, i was setting the every entry to reddis hash. After that i was mapping reddis hashes to java map and iterating on them in end of the process for min, max values. It seems so slow because if i call 100000 entry, program iterates x3 for min, max and avg. So i tried to do that with a Lua script. After publishing a message i set a start time to hash map and when listener gets message i take that messages start time from hash and i calculate difference with System.currentTimeMillis. After this step i am trying to execute Lua Script that compares the current value with older value and sets it. But when i execute the script it seems program stops there. I event tried just returning true from Lua script but i couldn't get any response.

 private void calculateSetANDLogAgain(User user){
        long startTime = ((long) redisTemplate.opsForHash().get("times", user.getId()));
        logger.info("Received message -> " + user.toString());
        long duration = 0L;
        duration = System.currentTimeMillis() - startTime;
        Object[] args = new Object[1];
        args[0] = duration;
        System.out.println("BEFORE");
        boolean a = redisTemplate.execute(statisticScript, Collections.singletonList("a"),args);
        System.out.println("AFTER: " + a);
    }

Here i see BEFORE but I cant see AFTER printing. Here is the log output and configuration about script executing. And here is my class tree. Note that RedisConfig class has the bean below.

 @Bean
    public DefaultRedisScript<Boolean> redisscript(){
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setLocation(new ClassPathResource("statistics.lua"));
        defaultRedisScript.setResultType(Boolean.class);
        return defaultRedisScript;
    }

And i am autowiring DefaultRedisScript instance in the class that owns calculateSetANDLogAgain method. Script file just have "return true;"

edit; here is my first script if it helps.

local difference = tonumber(ARGV[1])
local max = tonumber(redis.call("GET","max"))
local min = tonumber(redis.call("GET","min"))
if max == nil then
    redis.call("SET","max",difference)
elseif difference > max then
    redis.call("SET","max",difference)
end
if min == nil then
    redis.call("SET","min",difference)
elseif difference < min then
    redis.call("SET","min",difference)
end

So what may go wrong? I couldn't figured it out...

Upvotes: 1

Views: 2685

Answers (1)

Kadir Akin
Kadir Akin

Reputation: 101

I solved the problem. It is bizarre but it seems source of the failure is the wrong classpath. I made some changes in my code so take a look.

Here is the Bean definition.

   @Bean
    public DefaultRedisScript<Boolean> redisscript() {
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript<Boolean>();
        defaultRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("statistics.lua")));
        defaultRedisScript.setResultType(Boolean.class);
        return defaultRedisScript;
    }

Here is the calculateSetANDLogAgain function.

    private void calculateSetANDLogAgain(User user) {
        long startTime = ((long) redisTemplate.opsForHash().get("times", user.getId()));
        logger.info("Received message -> " + user.toString());
        Long duration = null;
        duration = System.currentTimeMillis() - startTime;
        Object[] args = new Object[1];
        args[0] = duration;
        try {
            redisTemplate.execute(statisticScript, null, args);
        } catch (Exception e) {
            finalLogger.info("Error while executing script -> " + e.getLocalizedMessage());
        }
    }

Here is the script;

local difference = tonumber(ARGV[1])
local max = tonumber(redis.call("GET","max"))
local min = tonumber(redis.call("GET","min"))
if max == nil then
    redis.call("SET","max",tostring(difference));
elseif difference > max then
    redis.call("SET","max",tostring(difference));
end

if min == nil then
    redis.call("SET","min",tostring(difference));
elseif difference < min then
    redis.call("SET","min",tostring(difference));
end
return nil;

Finally my script in resources folder and i injected the redistemplate in constructor.

Upvotes: 2

Related Questions