I had the same problem. I am developing some database data services using Redis as a cache repository through Spring Caching annotations. If the Redis server becomes unavailable, I want the services to continue to run as non-cached, rather than throwing exceptions.
First I tried a custom CacheErrorHandler, a mechanism provided by Spring. This didn't quite work, because it only handles RuntimeExceptions and still allows things like java.net.ConnectException to explode things.
In the end, I made a RedisTemplate extension, overriding several execute () methods to write warnings instead of throwing exceptions. It looks like a hack, and I could override too few execute () methods or too many, but in all my test cases it works like a charm.
However, there is an important operational aspect to this approach. If the Redis server becomes unavailable, you must clear it (clear records) before making it available again. Otherwise, it is likely that you may start retrieving cache entries with invalid data due to updates that have occurred during this time.
Below is the source. Feel free to use it. I hope this helps.
import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SessionCallback; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.serializer.RedisSerializer; public class LoggingRedisTemplate<K, V> extends RedisTemplate<K, V> { private static final Logger logger = LoggerFactory.getLogger(LoggingRedisTemplate.class); @Override public <T> T execute(final RedisCallback<T> action, final boolean exposeConnection, final boolean pipeline) { try { return super.execute(action, exposeConnection, pipeline); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final RedisScript<T> script, final List<K> keys, final Object... args) { try { return super.execute(script, keys, args); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final RedisScript<T> script, final RedisSerializer<?> argsSerializer, final RedisSerializer<T> resultSerializer, final List<K> keys, final Object... args) { try { return super.execute(script, argsSerializer, resultSerializer, keys, args); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final SessionCallback<T> session) { try { return super.execute(session); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } }