Redis
 sql >> Base de données >  >> NoSQL >> Redis

Poignée d'erreur Spring Redis

J'ai eu le même problème. Je développe des services de données sur une base de données, en utilisant Redis comme magasin de cache au moyen d'annotations Spring Caching. Si le serveur Redis devient indisponible, je souhaite que les services continuent de fonctionner comme s'ils n'étaient pas en cache, plutôt que de lever des exceptions.

Au début, j'ai essayé un CacheErrorHandler personnalisé, un mécanisme fourni par Spring. Cela n'a pas tout à fait fonctionné, car il ne gère que les RuntimeExceptions et laisse toujours des choses comme java.net.ConnectException exploser.

En fin de compte, ce que j'ai fait est d'étendre RedisTemplate, en remplaçant quelques méthodes execute() afin qu'elles consignent les avertissements au lieu de propager les exceptions. Cela ressemble un peu à un hack, et j'ai peut-être remplacé trop peu de méthodes execute() ou trop, mais cela fonctionne comme un charme dans tous mes cas de test.

Il y a cependant un aspect opérationnel important à cette approche. Si le serveur Redis devient indisponible, vous devez le vider (nettoyer les entrées) avant de le rendre à nouveau disponible. Sinon, il est possible que vous commenciez à récupérer des entrées de cache contenant des données incorrectes en raison de mises à jour effectuées entre-temps.

Ci-dessous la source. Sentez-vous libre de l'utiliser. J'espère que ça aide.

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;
        }
    }
}