Skip to content

MULTI is dispatched to slave nodes using SLAVE readFrom #779

@Yipei

Description

@Yipei

Hi there,

We are experiencing an issue on multi/exec transactions with master/slave configurations (readFrom is set as SLAVE). We are using spring-data-redis and selected lettuce as the redis framework.

Here is the code we wrote to catch the issue

RedisConnection connection= RedisConnectionUtils.getConnection(stringRedisTemplate.getConnectionFactory(), true);
      try {
                connection.watch(key.getBytes());
                connection.multi();                  
                connection.hashCommands().hMSet(key.getBytes(), hash);
                connection.exec();
        } catch (Exception e) {
        } finally {
            RedisConnectionUtils.releaseConnection(connection, stringRedisTemplate.getConnectionFactory());
        }

We set a master and slave to test it out
hosts:
- 127.0.0.1:6379 (master)
- 127.0.0.1:6380

Then we hit the exception
nested exception is io.lettuce.core.RedisCommandExecutionException: ERR EXEC without MULTI,
And we found the the watch(), multi(), exec() are distributed between the master and slave.

MASTER
[0 127.0.0.1:54159] "WATCH" "xxxx"
[0 127.0.0.1:54159] "HMSET" "xxxx"

SLAVE
[0 127.0.0.1:54157] "PING" "NODES"
[0 127.0.0.1:54160] "MULTI"

This could explain why the "ERR EXEC without MULTI" happens. But is this a bug or there is a way to work around? We also tried with stringRedisTemplate.execute(new SessionCallback<Boolean>(){...} but there are no difference.

Right now What I can think about is to have another ConnectionFactory with readFrom -> MASTER, and move all transactional commands to its maintained connections. But this looks like a ugly fix... Please advice.

I also saw a comment in another ticket : "Lettuce connections require single-threaded/synchronized access when using transactions. If two or more threads call concurrently MULTI/EXEC methods this will destroy the connection state. I don't think there is anything we could do here." Wondering the "single-threaded/synchronized" requirement mentioned there is to the RedisConnection or to the shared native connection?

Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions