Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Spring Redis-Fehlerhandle

Ich hatte das gleiche Problem. Ich entwickle einige Datendienste für eine Datenbank und verwende Redis als Cache-Speicher über Spring Caching-Anmerkungen. Wenn der Redis-Server nicht verfügbar ist, möchte ich, dass die Dienste weiterhin so funktionieren, als ob sie nicht zwischengespeichert wären, anstatt Ausnahmen auszulösen.

Zuerst habe ich einen benutzerdefinierten CacheErrorHandler ausprobiert, einen Mechanismus, der von Spring bereitgestellt wird. Es hat nicht ganz funktioniert, weil es nur RuntimeExceptions handhabt und Dinge wie java.net.ConnectException Dinge in die Luft jagen lässt.

Am Ende habe ich RedisTemplate erweitert und einige execute()-Methoden überschrieben, sodass sie Warnungen protokollieren, anstatt Ausnahmen zu verbreiten. Es scheint ein bisschen wie ein Hack zu sein, und ich habe vielleicht zu wenige oder zu viele execute()-Methoden überschrieben, aber es funktioniert wie ein Zauber in all meinen Testfällen.

Dieser Ansatz hat jedoch einen wichtigen operativen Aspekt. Wenn der Redis-Server nicht mehr verfügbar ist, müssen Sie ihn leeren (die Einträge löschen), bevor Sie ihn wieder verfügbar machen. Andernfalls besteht die Möglichkeit, dass Sie aufgrund von zwischenzeitlich erfolgten Aktualisierungen anfangen, Cache-Einträge abzurufen, die falsche Daten enthalten.

Unten ist die Quelle. Fühlen Sie sich frei, es zu benutzen. Ich hoffe, es hilft.

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