#spring-data-redis
#spring-data-redis
Вопрос:
Я столкнулся со случаем, когда redis pubsub RedisMessageListenerContainer
в моем приложении spring boot умер с
ERROR .RedisMessageListenerContainer: SubscriptionTask aborted with exception:
org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is com.lambdaworks.redis.RedisCommandTimeoutException: Command timed out
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:66)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:37)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:37)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:330)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.subscribe(LettuceConnection.java:3179)
at org.springframework.data.redis.listener.RedisMessageListenerContainer$SubscriptionTask.eventuallyPerformSubscription(RedisMessageListenerContainer.java:790)
at org.springframework.data.redis.listener.RedisMessageListenerContainer$SubscriptionTask.run(RedisMessageListenerContainer.java:746)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.lambdaworks.redis.RedisCommandTimeoutException: Command timed out
at com.lambdaworks.redis.LettuceFutures.await(LettuceFutures.java:113)
at com.lambdaworks.redis.LettuceFutures.awaitOrCancel(LettuceFutures.java:92)
at com.lambdaworks.redis.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:63)
at com.lambdaworks.redis.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
at com.sun.proxy.$Proxy156.subscribe(Unknown Source)
at org.springframework.data.redis.connection.lettuce.LettuceSubscription.doSubscribe(LettuceSubscription.java:63)
at org.springframework.data.redis.connection.util.AbstractSubscription.subscribe(AbstractSubscription.java:142)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.subscribe(LettuceConnection.java:3176)
... 3 common frames omitted
..
Я думаю, что это не должно быть неустранимой ошибкой в первую очередь, потому что это временная проблема с подключением (и TransientDataAccessException
), но приложению, по-видимому, необходимо иметь дело с исключениями в этом случае.
В настоящее время это оставляет приложение в неприемлемом состоянии. Он просто регистрирует ошибку, но мне нужно либо убить приложение, чтобы оно было заменено, либо лучше попытаться перезапустить этот контейнер и в идеале сообщить, /health
что приложение затронуто, если оно не все хорошо.
Есть ли что-нибудь, что я упускаю из виду, что менее неудобно, чем пытаться start()
использовать контейнер каждые x секунд или подклассировать его, перезаписать handleSubscriptionException()
и попытаться действовать оттуда? Последнее требует гораздо более глубокой интеграции с внутренними компонентами, чем я хотел бы иметь в своем коде, но это то, с чем я до сих пор работал:
RedisMessageListenerContainer container = new RedisMessageListenerContainer() {
@Override
protected void handleSubscriptionException(Throwable ex) {
super.handleSubscriptionException(ex); // don't know what actually happened in here and no way to find out :/
if (ex instanceof RedisConnectionFailureException) {
// handled by super hopefully, don't care
} else if (ex instanceof InterruptedException){
// can ignore those I guess
} else if (ex instanceof TransientDataAccessException || ex instanceof RecoverableDataAccessException) {
// try to restart in those cases?
if (isRunning()) {
logger.error("Connection failure occurred. Restarting subscription task manually due to " ex, ex);
sleepBeforeRecoveryAttempt();
start(); // best we can do
}
} else {
// otherwise shutdown and hope for the best next time
if (isRunning()) {
logger.warn("Shutting down application due to unknown exception " ex, ex);
context.close();
}
}
}
};