From 518fd6d94629f8ff7ca5a03c0061daa841dd1378 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 12 Nov 2021 08:51:41 +0100 Subject: [PATCH] Avoid cast to StatefulRedisConnection upon eager LettuceConnectionFactory initialization. We now no longer try to cast the Lettuce connection to StatefulRedisConnection when eagerly initializing the shared connection. Instead, we now introduced another method to obtain the cluster connection. Closes #2186 --- .../lettuce/LettuceConnectionFactory.java | 32 ++++++++++--- .../LettuceConnectionFactoryTests.java | 47 +++++++++++++++++-- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index a7fb2c196..9f0cb1ac5 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -438,9 +438,7 @@ public class LettuceConnectionFactory RedisClusterClient clusterClient = (RedisClusterClient) client; - StatefulRedisClusterConnection sharedConnection = getShareNativeConnection() - ? (StatefulRedisClusterConnection) getOrCreateSharedConnection().getConnection() - : null; + StatefulRedisClusterConnection sharedConnection = getSharedClusterConnection(); LettuceClusterTopologyProvider topologyProvider = new LettuceClusterTopologyProvider(clusterClient); return doCreateLettuceClusterConnection(sharedConnection, connectionProvider, topologyProvider, @@ -540,7 +538,12 @@ public class LettuceConnectionFactory resetConnection(); - getSharedConnection(); + if (isClusterAware()) { + getSharedClusterConnection(); + } else { + getSharedConnection(); + } + getSharedReactiveConnection(); } @@ -1081,12 +1084,27 @@ public class LettuceConnectionFactory } /** - * @return the shared connection using {@literal byte} array encoding for imperative API use. {@literal null} if - * {@link #getShareNativeConnection() connection sharing} is disabled. + * @return the shared connection using {@literal byte[]} encoding for imperative API use. {@literal null} if + * {@link #getShareNativeConnection() connection sharing} is disabled or when connected to Redis Cluster. */ @Nullable protected StatefulRedisConnection getSharedConnection() { - return shareNativeConnection ? (StatefulRedisConnection) getOrCreateSharedConnection().getConnection() : null; + return shareNativeConnection && !isClusterAware() + ? (StatefulRedisConnection) getOrCreateSharedConnection().getConnection() + : null; + } + + /** + * @return the shared cluster connection using {@literal byte[]} encoding for imperative API use. {@literal null} if + * {@link #getShareNativeConnection() connection sharing} is disabled or when connected to Redis + * Standalone/Sentinel/Master-Replica. + * @since 2.5.7 + */ + @Nullable + protected StatefulRedisClusterConnection getSharedClusterConnection() { + return shareNativeConnection && isClusterAware() + ? (StatefulRedisClusterConnection) getOrCreateSharedConnection().getConnection() + : null; } /** diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index 9f0518317..6bd0750e6 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -48,6 +48,7 @@ import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration; import org.springframework.data.redis.connection.StringRedisConnection; import org.springframework.data.redis.connection.lettuce.extension.LettuceConnectionFactoryExtension; +import org.springframework.data.redis.test.condition.EnabledOnRedisClusterAvailable; import org.springframework.data.redis.test.extension.LettuceTestClientResources; /** @@ -85,7 +86,6 @@ class LettuceConnectionFactoryTests { factory.destroy(); } - @SuppressWarnings("rawtypes") @Test void testGetNewConnectionOnError() throws Exception { @@ -462,9 +462,8 @@ class LettuceConnectionFactoryTests { RedisConnection connection = factory.getConnection(); - assertThatThrownBy(() -> connection.pSubscribe((message, pattern) -> { - }, "foo".getBytes())).isInstanceOf(RedisConnectionFailureException.class) - .hasCauseInstanceOf(UnsupportedOperationException.class); + assertThatThrownBy(() -> connection.pSubscribe((message, pattern) -> {}, "foo".getBytes())) + .isInstanceOf(RedisConnectionFailureException.class).hasCauseInstanceOf(UnsupportedOperationException.class); connection.close(); factory.destroy(); @@ -558,4 +557,44 @@ class LettuceConnectionFactoryTests { connection.close(); } + + @Test // GH-2186 + void shouldInitializeMasterReplicaConnectionsEagerly() { + + LettuceClientConfiguration configuration = LettuceClientConfiguration.builder() + .clientResources(LettuceTestClientResources.getSharedClientResources()).build(); + + RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration( + SettingsUtils.getHost()).node(SettingsUtils.getHost(), SettingsUtils.getPort() + 1); + + LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache, configuration); + factory.setEagerInitialization(true); + factory.afterPropertiesSet(); + + assertThat(factory.getSharedConnection()).isNotNull(); + assertThat(factory.getSharedClusterConnection()).isNull(); + + factory.getConnection().close(); + factory.destroy(); + } + + @Test // GH-2186 + @EnabledOnRedisClusterAvailable + void shouldInitializeClusterConnectionsEagerly() { + + LettuceClientConfiguration configuration = LettuceClientConfiguration.builder() + .clientResources(LettuceTestClientResources.getSharedClientResources()).build(); + + LettuceConnectionFactory factory = new LettuceConnectionFactory(SettingsUtils.clusterConfiguration(), + configuration); + factory.setEagerInitialization(true); + factory.afterPropertiesSet(); + + assertThat(factory.getSharedConnection()).isNull(); + assertThat(factory.getSharedClusterConnection()).isNotNull(); + + factory.getConnection().close(); + factory.destroy(); + } + }