redis / lettuce

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
https://lettuce.io
MIT License
5.37k stars 962 forks source link

nested exception is java.lang.UnsupportedOperationException: io.lettuce.core.output.ValueOutput does not support set(long) #2831

Closed Memorydoc closed 4 months ago

Memorydoc commented 5 months ago

Our service encountered ValueOutput does not support set(long) exception, which was automatically recovered after service restart. Strange scenario. How do we solve this?

image
tishun commented 5 months ago

Hey @Memorydoc , from the exception name (org.springframework.data.redis.RedisSystemException) I can only assume you are having issue with the Spring Data Redis and not the Lettuce driver itself?

Anyway to understand the issue better we will need more information like a complete stacktrace or a sample of the code that ptoduces this issue.

ShepherdZFJ commented 5 months ago

I encountered the same problem when upgrading from Spring boot2.3.4 to 2.7.0 The code example is as follows:

   @Test
    public void test() {
        StringBuilder lua = new StringBuilder();
        lua.append("local c");
        lua.append("\nc = redis.call('get',KEYS[1])");
        lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");
        lua.append("\nreturn c;");
        lua.append("\nend");
        lua.append("\nc = redis.call('incr',KEYS[1])");
        lua.append("\nif tonumber(c) == 1 then");
        lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");
        lua.append("\nend");
        lua.append("\nreturn c;");
        int limitCount = 10;
        int limitPeriod = 3;
        List<String> keys = new ArrayList<>();
        keys.add("kk");
        RedisScript<Number> redisScript = new DefaultRedisScript<>(lua.toString(), Number.class);
        Number count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limitCount), String.valueOf(limitPeriod));
        System.out.println(count);
    }

The debug code enters the execute method of the DefaultScriptExecutor class of spring-data-redis

public <T> T execute(final RedisScript<T> script, final RedisSerializer<?> argsSerializer,
            final RedisSerializer<T> resultSerializer, final List<K> keys, final Object... args) {
        return template.execute((RedisCallback<T>) connection -> {
            final ReturnType returnType = ReturnType.fromJavaType(script.getResultType());
            final byte[][] keysAndArgs = keysAndArgs(argsSerializer, keys, args);
            final int keySize = keys != null ? keys.size() : 0;
            if (connection.isPipelined() || connection.isQueueing()) {
                // We could script load first and then do evalsha to ensure sha is present,
                // but this adds a sha1 to exec/closePipeline results. Instead, just eval
                connection.eval(scriptBytes(script), returnType, keySize, keysAndArgs);
                return null;
            }
            return eval(connection, script, returnType, keySize, keysAndArgs, resultSerializer);
        });
    }

In version 2.3.4, the ReturnType is Integer and IntegerOutPut will be generated, but in version 2.7.0, the ReturnType is VALUEand generates ValueOutPut, resulting in the above error, so I think ValueOutPut should support the processing of Number, which can solve this problem.

tishun commented 4 months ago

@Memorydoc , @ShepherdZFJ , Seems to me this is deffinetly an issue with spring-data-redis, perhaps sometihng like https://github.com/spring-projects/spring-data-redis/issues/2908

This project works on the underlying driver and - unless the driver is the problem - there is nothing to be done in Lettuce.

Closing this, please reopen if you have some indications that the issue is in the Lettuce code.