Ik had hetzelfde probleem. Ik ontwikkel een aantal gegevensservices voor een database, waarbij ik Redis als cacheopslag gebruik door middel van Spring Caching-annotaties. Als de Redis-server niet meer beschikbaar is, wil ik dat de services blijven werken alsof ze niet in de cache zijn opgeslagen, in plaats van uitzonderingen te genereren.
In eerste instantie probeerde ik een aangepaste CacheErrorHandler, een mechanisme geleverd door Spring. Het werkte niet helemaal, omdat het alleen RuntimeExceptions afhandelt en nog steeds dingen als java.net.ConnectException laat opblazen.
Uiteindelijk heb ik RedisTemplate uitgebreid, waarbij ik een paar execute()-methoden heb genegeerd, zodat ze waarschuwingen loggen in plaats van uitzonderingen te verspreiden. Het lijkt een beetje een hack, en ik heb misschien te weinig execute()-methoden of te veel overschreven, maar het werkt als een charme in al mijn testgevallen.
Er is echter een belangrijk operationeel aspect aan deze aanpak. Als de Redis-server niet meer beschikbaar is, moet u deze leegmaken (de vermeldingen opschonen) voordat u deze weer beschikbaar maakt. Anders bestaat de kans dat u cache-items gaat ophalen die onjuiste gegevens bevatten vanwege updates die in de tussentijd hebben plaatsgevonden.
Hieronder staat de bron. Voel je vrij om het te gebruiken. Ik hoop dat het helpt.
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;
}
}
}