1 year ago

#387508

test-img

jimonthebarn

How to properly close Redis connection on intentional application shutdown?

We are using the list operations of the RedisTemplate (provided by spring-boot-starter-data-redis) to do a blocking call waiting for new items to arrive in a list within Redis. Since we are not listening to a single list but multiple ones we do this on a separate thread for each blocking list command call. That all works quite well until we shutdown the application (e.g. when running integration tests where the Redis is actually a testcontainer instance that is shut down after test execution) at which point we experience a myriad of stack traces resulting from the sudden shutdown of the Redis instance leading to the RedisCommandInterruptedExceptions as well as the ConnectionWatchdog trying to reconnect to the Redis instance which has already died:

15:19:10.352 [lettuce-eventExecutorLoop-1-4] INFO  io.lettuce.core.protocol.ConnectionWatchdog - Reconnecting, last destination was localhost/127.0.0.1:56344

Caused by: io.lettuce.core.RedisCommandInterruptedException: Command interrupted
    at io.lettuce.core.protocol.AsyncCommand.await(AsyncCommand.java:87)
    at io.lettuce.core.internal.Futures.awaitOrCancel(Futures.java:244)
    at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:74)
    at org.springframework.data.redis.connection.lettuce.LettuceConnection.await(LettuceConnection.java:1061)

org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 172.17.0.1:56344

Is there a way to properly close the Redis connections and disable the ConnectionWatchDog for an intentional shutdown of the application?

Below is the simplified setup we currently have in place for the Redis wait:

@Component
@RequiredArgsConstructor
public class CustomMessageListener {

    private final RedisTemplate<String, CustomMessage> template;

    @Async("listeningExecutor")
    public void listen(String list, AtomicBoolean keepListening) {
        ListOperations<String, CustomMessage> listOperations = template.opsForList();
        while (keepListening.get()) {
            try {
                var message = listOperations.rightPop(list, Duration.ofSeconds(10))
                if (message != null) {
                    // do something with the message
                }
            } catch (Exception e) {
                // log exception
            }
        }
    }
}

spring-data-redis

0 Answers

Your Answer

Accepted video resources