sql >> Base de Datos >  >> NoSQL >> Redis

Manejador de error Spring Redis

Tuve el mismo problema. Estoy desarrollando algunos servicios de datos en una base de datos, utilizando Redis como almacén de caché a través de las anotaciones de Spring Caching. Si el servidor de Redis deja de estar disponible, quiero que los servicios continúen funcionando como si no estuvieran en caché, en lugar de generar excepciones.

Al principio probé un CacheErrorHandler personalizado, un mecanismo provisto por Spring. No funcionó del todo, porque solo maneja RuntimeExceptions, y todavía permite que cosas como java.net.ConnectException exploten.

Al final, lo que hice fue extender RedisTemplate, anulando algunos métodos de ejecución () para que registren advertencias en lugar de propagar excepciones. Parece un truco, y es posible que haya anulado muy pocos métodos de ejecución () o demasiados, pero funciona de maravilla en todos mis casos de prueba.

Sin embargo, hay un aspecto operativo importante en este enfoque. Si el servidor Redis deja de estar disponible, debe vaciarlo (limpiar las entradas) antes de que vuelva a estar disponible. De lo contrario, existe la posibilidad de que comience a recuperar entradas de caché que tienen datos incorrectos debido a las actualizaciones que se produjeron mientras tanto.

A continuación se muestra la fuente. Sientase libre de usarlo. Espero que ayude.

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