Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Redis - Custom error handling

I have a Spring Boot rest api using Spring Data Redis.

My aim is to make redis 'transparent' for the application. Is redis is there, use it, if not do not throw any exception and runs normally.

My first step was to create a custom cache error handler

@Configuration
public class CustomCacheConfiguration extends CachingConfigurerSupport {

    @Override
    public CacheErrorHandler errorHandler() {
        return new CustomCacheErrorHandler();
    }

}

and

@Slf4j
public class CustomCacheErrorHandler implements CacheErrorHandler {

    @Override
    public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
        log.error(String.format("Unable to get data from cache : %s", exception.getMessage()));
    }
    @Override
    public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
        log.error(String.format("Unable to put data into the cache : %s", exception.getMessage()));
    }
    @Override
    public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
        log.error(String.format("Unable to evict data from cache : %s", exception.getMessage()));
    }
    @Override
    public void handleCacheClearError(RuntimeException exception, Cache cache) {
        log.error(String.format("Unable to clear data from cache : %s", exception.getMessage()));
    }

}

It is working fine. If redis is not up no more exception, just an error in the logs and the api keeps working normally.

But it remains one problem. If redis is going down after the application is started. In that case :

  • the api hangs when trying to lookup in the cache an takes more than 2 minutes to respond in place of less than few seconds.

  • in the logs (not even every minute) I can see :

    2022-07-01 10:01:11.636  INFO 7004 --- [xecutorLoop-1-1] i.l.core.protocol.ConnectionWatchdog     : Reconnecting, last destination was localhost/<unresolved>:6379
    2022-07-01 10:01:11.638  WARN 7004 --- [ioEventLoop-4-7] i.l.core.protocol.ConnectionWatchdog     : Cannot reconnect to [localhost/<unresolved>:6379]: Connection refused: no further information: localhost/127.0.0.1:6379
    

Is there a way of resolving point 1 and avoiding point 2 ?

like image 798
tweetysat Avatar asked Jul 11 '26 06:07

tweetysat


1 Answers

i've faced the same issue. I discover that the timeout value is the one set by the redis client used. In my case it is the lettuce timeout with a default value of 60 seconds. So to have a custom value, you have to change the lettuce client timeout when instantiating the LettuceClientConfiguration:

LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder().commandTimeout(Duration.ofMillis(333)).build();

and then when creating the lettuce connection pass the custom client:

connFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port), clientConfig);

The LettuceConnectionFactory has several constructors. It is important to pass the custom client to your chosen constructor. If no client configuration is passed, the default one is the MutableLettuceClientConfiguration class. Default value are:

static class MutableLettuceClientConfiguration implements LettuceClientConfiguration {

        private boolean useSsl;
        private boolean verifyPeer = true;
        private boolean startTls;
        private @Nullable ClientResources clientResources;
        private @Nullable String clientName;
        private Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT);
        private Duration shutdownTimeout = Duration.ofMillis(100); 
        [...]
        }

Note that Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT) has value 60 seconds.

like image 151
Evandro Maddes Avatar answered Jul 14 '26 10:07

Evandro Maddes