Имах същия проблем. Разработвам някои услуги за данни спрямо база данни, като използвам Redis като кеш хранилище чрез анотации за Spring Caching. Ако Redis сървърът стане недостъпен, искам услугите да продължат да работят като некеширани, вместо да хвърлят изключения.
Първо опитах персонализиран CacheErrorHandler, механизъм, предоставен от Spring. Не проработи съвсем, защото обработва само RuntimeExceptions и все пак позволява на неща като java.net.ConnectException да раздуват нещата.
В крайна сметка това, което направих, е да разширя RedisTemplate, заменяйки няколко метода execute(), така че да регистрират предупреждения, вместо да разпространяват изключения. Изглежда като хак и може да съм заменил твърде малко методи execute() или твърде много, но работи като чар във всичките ми тестови случаи.
Този подход обаче има важен оперативен аспект. Ако Redis сървърът стане недостъпен, трябва да го изчистите (изчистите записите), преди да го направите отново достъпен. В противен случай има вероятност да започнете да извличате записи в кеша, които имат неправилни данни поради актуализации, настъпили междувременно.
По-долу е източникът. Чувствайте се свободни да го използвате. Надявам се да помогне.
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;
/**
* An extension of RedisTemplate that logs exceptions instead of letting them propagate.
* If the Redis server is unavailable, cache operations are always a "miss" and data is fetched from the database.
*/
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;
}
}
}