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 ?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With