Skip to content

Commit c600d0e

Browse files
committed
Polishing.
We now ensure proper exception handling in connection close methods to avoid resource leaks. Also, exceptions during connection close are no longer thrown to ensure proper resource cleanup behavior and API design. See #2356
1 parent ed81639 commit c600d0e

File tree

2 files changed

+34
-18
lines changed

2 files changed

+34
-18
lines changed

src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import java.util.Map;
2020
import java.util.concurrent.ConcurrentHashMap;
2121

22+
import org.apache.commons.logging.Log;
23+
import org.apache.commons.logging.LogFactory;
24+
2225
import org.springframework.dao.DataAccessException;
2326
import org.springframework.dao.InvalidDataAccessApiUsageException;
2427
import org.springframework.dao.InvalidDataAccessResourceUsageException;
25-
import org.springframework.data.redis.RedisSystemException;
2628
import org.springframework.lang.Nullable;
2729
import org.springframework.util.Assert;
2830

@@ -33,6 +35,8 @@
3335
*/
3436
public abstract class AbstractRedisConnection implements RedisConnection {
3537

38+
private final Log LOGGER = LogFactory.getLog(getClass());
39+
3640
private @Nullable RedisSentinelConfiguration sentinelConfiguration;
3741
private final Map<RedisNode, RedisSentinelConnection> connectionCache = new ConcurrentHashMap<>();
3842

@@ -96,18 +100,23 @@ protected RedisSentinelConnection getSentinelConnection(RedisNode sentinel) {
96100
@Override
97101
public void close() throws DataAccessException {
98102

99-
if (!connectionCache.isEmpty()) {
100-
for (RedisNode node : connectionCache.keySet()) {
101-
RedisSentinelConnection connection = connectionCache.remove(node);
102-
if (connection.isOpen()) {
103-
try {
104-
connection.close();
105-
} catch (IOException e) {
106-
throw new RedisSystemException("Failed to close sentinel connection", e);
107-
}
108-
}
103+
if (connectionCache.isEmpty()) {
104+
return;
105+
}
106+
107+
for (RedisNode node : connectionCache.keySet()) {
108+
109+
RedisSentinelConnection connection = connectionCache.remove(node);
110+
111+
if (!connection.isOpen()) {
112+
continue;
113+
}
114+
115+
try {
116+
connection.close();
117+
} catch (IOException e) {
118+
LOGGER.info("Failed to close sentinel connection", e);
109119
}
110120
}
111121
}
112-
113122
}

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
import java.util.concurrent.atomic.AtomicLong;
5656
import java.util.function.Supplier;
5757

58+
import org.apache.commons.logging.Log;
59+
import org.apache.commons.logging.LogFactory;
60+
5861
import org.springframework.beans.BeanUtils;
5962
import org.springframework.core.convert.converter.Converter;
6063
import org.springframework.dao.DataAccessException;
@@ -90,6 +93,8 @@
9093
*/
9194
public class LettuceConnection extends AbstractRedisConnection {
9295

96+
private final Log LOGGER = LogFactory.getLog(getClass());
97+
9398
static final RedisCodec<byte[], byte[]> CODEC = ByteArrayCodec.INSTANCE;
9499

95100
private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy(
@@ -342,7 +347,7 @@ public Object execute(String command, @Nullable CommandOutput commandOutputTypeH
342347
}
343348

344349
@Override
345-
public void close() throws DataAccessException {
350+
public void close() {
346351

347352
super.close();
348353

@@ -352,7 +357,11 @@ public void close() throws DataAccessException {
352357

353358
isClosed = true;
354359

355-
reset();
360+
try {
361+
reset();
362+
} catch (RuntimeException e) {
363+
LOGGER.debug("Failed to reset connection during close", e);
364+
}
356365
}
357366

358367
private void reset() {
@@ -629,8 +638,7 @@ public void pSubscribe(MessageListener listener, byte[]... patterns) {
629638
checkSubscription();
630639

631640
if (isQueueing() || isPipelined()) {
632-
throw new InvalidDataAccessApiUsageException(
633-
"Transaction/Pipelining is not supported for Pub/Sub subscriptions");
641+
throw new InvalidDataAccessApiUsageException("Transaction/Pipelining is not supported for Pub/Sub subscriptions");
634642
}
635643

636644
try {
@@ -647,8 +655,7 @@ public void subscribe(MessageListener listener, byte[]... channels) {
647655
checkSubscription();
648656

649657
if (isQueueing() || isPipelined()) {
650-
throw new InvalidDataAccessApiUsageException(
651-
"Transaction/Pipelining is not supported for Pub/Sub subscriptions");
658+
throw new InvalidDataAccessApiUsageException("Transaction/Pipelining is not supported for Pub/Sub subscriptions");
652659
}
653660

654661
try {

0 commit comments

Comments
 (0)