Skip to content

After timeout occurs on MULTI call every following transaction fails #2865

Closed
@BadEvil1

Description

@BadEvil1

I have a piece of code:

stringRedisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.multi();
            ///some logic
            connection.exec();
            }

And timeout occurs on MULTI call:

"exception":{
      "message":"Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)",
      "stackTrace":"org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
      \tat org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70)
      \tat org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
      \tat org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
      \tat org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
      \tat org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:277)
      \tat org.springframework.data.redis.connection.lettuce.LettuceConnection.multi(LettuceConnection.java:659)
      \tat org.springframework.data.redis.core.RedisTemplate.lambda$multi$23(RedisTemplate.java:1032)
      \tat org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224)
      \tat org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191)
      \tat org.springframework.data.redis.core.RedisTemplate.multi(RedisTemplate.java:1031)

After that, any following MULTI invocation fails with the following exception:
RedisCommandExecutionException: ERR MULTI calls can not be nested

I was able to reproduce it with a live redis instance using redis-cli CLIENT PAUSE to simulate a timeout in redis.

Workaround:
I surrounded it with try/catch to call DISCARD manually:

stringRedisTemplate.execute((RedisCallback<Void>) connection -> {
          try {
           connection.multi();
           ///some logic
           connection.exec();
           } catch(QueryTimeoutException e) {
           connection.discard():
           }

Actually, I expected that it would not help if DISCARD failed because of the timeout, but even if the timeout happens DICARD rollbacks transaction somehow.

My env:
Java version: 17.0.9
spring-data-redis version: 2.7.15
redis version:3.2.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions