diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java index 608bd9d52..d1414020e 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.DirectFieldAccessor; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -58,12 +60,15 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( JedisConverters.exceptionConverter()); + private final Log log = LogFactory.getLog(getClass()); + private final JedisCluster cluster; private boolean closed; private final JedisClusterTopologyProvider topologyProvider; private ClusterCommandExecutor clusterCommandExecutor; + private final boolean disposeClusterCommandExecutorOnClose; private volatile JedisSubscription subscription; @@ -82,6 +87,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { topologyProvider = new JedisClusterTopologyProvider(cluster); clusterCommandExecutor = new ClusterCommandExecutor(topologyProvider, new JedisClusterNodeResourceProvider(cluster), EXCEPTION_TRANSLATION); + disposeClusterCommandExecutorOnClose = true; try { DirectFieldAccessor dfa = new DirectFieldAccessor(cluster); @@ -108,6 +114,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { this.cluster = cluster; this.topologyProvider = new JedisClusterTopologyProvider(cluster); this.clusterCommandExecutor = executor; + this.disposeClusterCommandExecutorOnClose = false; } /* @@ -366,9 +373,8 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { @Override public String ping() { - return !clusterCommandExecutor - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::ping).resultsAsList() - .isEmpty() ? "PONG" : null; + return !clusterCommandExecutor.executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::ping) + .resultsAsList().isEmpty() ? "PONG" : null; } @@ -588,11 +594,10 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); - return JedisConverters.toSetOfRedisClusterNodes( - clusterCommandExecutor - .executeCommandOnSingleNode( - (JedisClusterCommandCallback>) client -> client.clusterSlaves(nodeToUse.getId()), master) - .getValue()); + return JedisConverters.toSetOfRedisClusterNodes(clusterCommandExecutor + .executeCommandOnSingleNode( + (JedisClusterCommandCallback>) client -> client.clusterSlaves(nodeToUse.getId()), master) + .getValue()); } /* @@ -635,10 +640,8 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { @Override public ClusterInfo clusterGetClusterInfo() { - return new ClusterInfo(JedisConverters - .toProperties(clusterCommandExecutor - .executeCommandOnArbitraryNode((JedisClusterCommandCallback) Jedis::clusterInfo) - .getValue())); + return new ClusterInfo(JedisConverters.toProperties(clusterCommandExecutor + .executeCommandOnArbitraryNode((JedisClusterCommandCallback) Jedis::clusterInfo).getValue())); } /* @@ -655,6 +658,15 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { */ @Override public void close() throws DataAccessException { + + if (!closed && disposeClusterCommandExecutorOnClose) { + try { + clusterCommandExecutor.destroy(); + } catch (Exception ex) { + log.warn("Cannot properly close cluster command executor", ex); + } + } + closed = true; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index 0e96928f0..06d236f87 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -34,8 +34,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.DisposableBean; +import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; @@ -59,9 +62,12 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau new LettuceExceptionConverter()); static final RedisCodec CODEC = ByteArrayCodec.INSTANCE; + private final Log log = LogFactory.getLog(getClass()); + private final RedisClusterClient clusterClient; private ClusterCommandExecutor clusterCommandExecutor; private ClusterTopologyProvider topologyProvider; + private final boolean disposeClusterCommandExecutorOnClose; /** * Creates new {@link LettuceClusterConnection} using {@link RedisClusterClient}. @@ -78,6 +84,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau topologyProvider = new LettuceClusterTopologyProvider(clusterClient); clusterCommandExecutor = new ClusterCommandExecutor(topologyProvider, new LettuceClusterNodeResourceProvider(clusterClient), exceptionConverter); + disposeClusterCommandExecutorOnClose = true; } /** @@ -97,6 +104,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau this.clusterClient = clusterClient; topologyProvider = new LettuceClusterTopologyProvider(clusterClient); clusterCommandExecutor = executor; + disposeClusterCommandExecutorOnClose = false; } /* @@ -497,12 +505,10 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau @Override public Map> clusterGetMasterSlaveMap() { - List>> nodeResults = clusterCommandExecutor - .executeCommandAsyncOnNodes( - (LettuceClusterCommandCallback>) client -> Converters - .toSetOfRedisClusterNodes(client.clusterSlaves(client.clusterMyId())), - topologyProvider.getTopology().getActiveMasterNodes()) - .getResults(); + List>> nodeResults = clusterCommandExecutor.executeCommandAsyncOnNodes( + (LettuceClusterCommandCallback>) client -> Converters + .toSetOfRedisClusterNodes(client.clusterSlaves(client.clusterMyId())), + topologyProvider.getTopology().getActiveMasterNodes()).getResults(); Map> result = new LinkedHashMap<>(); @@ -517,6 +523,24 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau return clusterCommandExecutor; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#close() + */ + @Override + public void close() throws DataAccessException { + + if (!isClosed() && disposeClusterCommandExecutorOnClose) { + try { + clusterCommandExecutor.destroy(); + } catch (Exception ex) { + log.warn("Cannot properly close cluster command executor", ex); + } + } + + super.close(); + } + /** * Lettuce specific implementation of {@link ClusterCommandCallback}. * @@ -535,9 +559,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @since 1.7 */ protected interface LettuceMultiKeyClusterCommandCallback - extends MultiKeyClusterCommandCallback, T> { - - } + extends MultiKeyClusterCommandCallback, T> {} /** * Lettuce specific implementation of {@link ClusterNodeResourceProvider}.