Miałem ten sam problem. Zajmuję się tworzeniem niektórych usług danych względem bazy danych, używając Redis jako magazynu pamięci podręcznej za pomocą adnotacji Spring Caching. Jeśli serwer Redis stanie się niedostępny, chcę, aby usługi nadal działały bez buforowania, zamiast zgłaszać wyjątki.
Najpierw wypróbowałem niestandardowy CacheErrorHandler, mechanizm dostarczony przez Spring. To nie do końca działało, ponieważ obsługuje tylko wyjątki RuntimeException i nadal pozwala wysadzać rzeczy takie jak java.net.ConnectException.
W końcu rozszerzyłem RedisTemplate, nadpisując kilka metod execute(), aby rejestrowały ostrzeżenia zamiast propagować wyjątki. Wygląda na to, że to trochę hack i mogłem przesłonić zbyt mało lub zbyt wiele metod execute(), ale działa to jak urok we wszystkich moich przypadkach testowych.
Jest jednak ważny aspekt operacyjny w tym podejściu. Jeśli serwer Redis stanie się niedostępny, musisz go opróżnić (wyczyścić wpisy) przed ponownym udostępnieniem. W przeciwnym razie istnieje szansa, że możesz zacząć pobierać wpisy z pamięci podręcznej, które zawierają niepoprawne dane z powodu aktualizacji, które miały miejsce w międzyczasie.
Poniżej znajduje się źródło. Zapraszam do korzystania. Mam nadzieję, że to pomoże.
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;
}
}
}