Uploaded image for project: 'Spring Data Redis'
  1. Spring Data Redis
  2. DATAREDIS-908

Cannot execute RedisScript with SLAVE_PREFERRED option

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Invalid
    • Affects Version/s: 2.1.3 (Lovelace SR3)
    • Fix Version/s: None
    • Component/s: Lettuce Driver
    • Labels:
      None

      Description

      When using the LettuceClientConfiguration with option readFrom set to SLAVE_PREFERRED: we cannot execute LUA scripts. The setup is quite easy to reproduce with the following code :

      @Configuration
      @EnableScheduling
      public class RedisLockStarter {
          private static final Log logger = LogFactory.getLog(RedisLockStarter.class);
      
          @Autowired
          private LockRegistry registry;
      
          public static void main(String[] args) {
              new AnnotationConfigApplicationContext(RedisLockStarter.class);
          }
      
          @Bean
          public LettuceConnectionFactory connectionFactory() {
              LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                      .readFrom(SLAVE_PREFERRED)
                      .build();
              RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
                      .master("my-redis-master")
                      .sentinel("sentinel-address-1", 26379)
                      .sentinel("sentinel-address-2", 26379)
                      .sentinel("sentinel-address-3", 26379);
              sentinelConfig.setPassword(RedisPassword.of("my-password"));
              return new LettuceConnectionFactory(sentinelConfig, clientConfig);
          }
      
          @Bean
          LockRegistry lockRegistry(RedisConnectionFactory connectionFactory) {
              return new RedisLockRegistry(connectionFactory, "test", 10000);
          }
      
          @Scheduled(fixedDelay = 60000)
          public void tryLock() {
              try {
                  lockUnlock();
              } catch (Exception e) {
                  logger.fatal(e.getMessage(), e);
              }
          }
      
          private void lockUnlock() {
              Lock lock = registry.obtain("lock-1");
              lock.lock();
              try {
                  logger.info("Locked");
              } finally {
                  lock.unlock();
                  logger.info("Unlock");
              }
          }
      }

      This code will fail with the following stack trace : 

      17:45:14.338 [pool-1-thread-1] ERROR com.testing.lock.RedisLockStarter - Failed to lock mutex at test:lock-1; nested exception is org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_8426c8df41c64d8177dce3ecbbe9146ef3759cd2): @user_script:6: @user_script: 6: -READONLY You can't write against a read only slave.   17:45:14.338 [pool-1-thread-1] ERROR com.testing.lock.RedisLockStarter - Failed to lock mutex at test:lock-1; nested exception is org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_8426c8df41c64d8177dce3ecbbe9146ef3759cd2): @user_script:6: @user_script: 6: -READONLY You can't write against a read only slave.   org.springframework.dao.CannotAcquireLockException: Failed to lock mutex at test:lock-1; nested exception is org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_8426c8df41c64d8177dce3ecbbe9146ef3759cd2): @user_script:6: @user_script: 6: -READONLY You can't write against a read only slave.    at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.rethrowAsLockException(RedisLockRegistry.java:227) at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.lock(RedisLockRegistry.java:221) at com.testing.lock.RedisLockStarter.lockUnlock(RedisLockStarter.java:68) at com.testing.lock.RedisLockStarter.tryLock(RedisLockStarter.java:60) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)Caused by: org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_8426c8df41c64d8177dce3ecbbe9146ef3759cd2): @user_script:6: @user_script: 6: -READONLY You can't write against a read only slave.    at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:54) at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:52) at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41) at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44) at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42) at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:268) at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.convertLettuceAccessException(LettuceScriptingCommands.java:236) at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.evalSha(LettuceScriptingCommands.java:195) at org.springframework.data.redis.connection.DefaultedRedisConnection.evalSha(DefaultedRedisConnection.java:1318) at org.springframework.data.redis.connection.DefaultStringRedisConnection.evalSha(DefaultStringRedisConnection.java:1729) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61) at com.sun.proxy.$Proxy22.evalSha(Unknown Source) at org.springframework.data.redis.core.script.DefaultScriptExecutor.eval(DefaultScriptExecutor.java:77) at org.springframework.data.redis.core.script.DefaultScriptExecutor.lambda$execute$0(DefaultScriptExecutor.java:68) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:171) at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:58) at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:52) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:346) at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.obtainLock(RedisLockRegistry.java:285) at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.lock(RedisLockRegistry.java:207) ... 16 common frames omittedCaused by: io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_8426c8df41c64d8177dce3ecbbe9146ef3759cd2): @user_script:6: @user_script: 6: -READONLY You can't write against a read only slave.    at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135) at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108) at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120) at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111) at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:646) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:604) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:556) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ... 1 common frames omitted
      

      As a matter of fact any LUA script executed using the RedisTemplate class will fail when the option ".readFrom(SLAVE_PREFERRED)" is set.

       

      Spring versions used:

      Spring-Data-Redis : 2.1.3.RELEASE 

      Spring-Boot-Starter-Parent : 2.1.1.RELEASE

      Spring-Integration-Redis : 5.1.1.RELEASE

       

      Redis Setup:

      Version 3.2.12, 1 master, 2 slaves & 3 sentinels

       

       

        Attachments

          Activity

            People

            • Assignee:
              mp911de Mark Paluch
              Reporter:
              tlambert Tanguy Lambert
              Last updater:
              Mark Paluch
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: