Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Identificador de erro do Spring Redis


Eu tive o mesmo problema. Estou desenvolvendo alguns serviços de dados em um banco de dados, usando o Redis como armazenamento de cache por meio de anotações do Spring Caching. Se o servidor Redis ficar indisponível, quero que os serviços continuem operando como se não estivessem em cache, em vez de lançar exceções.

No começo eu tentei um CacheErrorHandler personalizado, um mecanismo fornecido pelo Spring. Não funcionou muito bem, porque só lida com RuntimeExceptions, e ainda deixa coisas como java.net.ConnectException explodir coisas.

No final, o que fiz foi estender o RedisTemplate, substituindo alguns métodos execute() para que eles registrem avisos em vez de propagar exceções. Parece um pouco um hack, e eu posso ter substituído poucos métodos execute() ou muitos, mas funciona como um encanto em todos os meus casos de teste.

No entanto, há um aspecto operacional importante nessa abordagem. Se o servidor Redis ficar indisponível, você deverá liberá-lo (limpar as entradas) antes de disponibilizá-lo novamente. Caso contrário, é possível que você comece a recuperar entradas de cache com dados incorretos devido a atualizações que ocorreram nesse meio tempo.

Abaixo está a fonte. Sinta-se livre para usá-lo. Espero que ajude.
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;
        }
    }
}