diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java index 6a89a2bd3d..dc883f6bd3 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java @@ -32,18 +32,33 @@ * @author Christoph Strobl * @author Yanming Zhou * @author Zhian Chen + * @author Asmir Mustafic * @since 2.0 */ class DefaultLettucePoolingClientConfiguration implements LettucePoolingClientConfiguration { private final LettuceClientConfiguration clientConfiguration; private final GenericObjectPoolConfig poolConfig; + private final boolean preparePool; DefaultLettucePoolingClientConfiguration(LettuceClientConfiguration clientConfiguration, GenericObjectPoolConfig poolConfig) { this.clientConfiguration = clientConfiguration; this.poolConfig = poolConfig; + this.preparePool = false; + } + + DefaultLettucePoolingClientConfiguration(LettuceClientConfiguration clientConfiguration, + GenericObjectPoolConfig poolConfig, boolean preparePool) { + this.clientConfiguration = clientConfiguration; + this.poolConfig = poolConfig; + this.preparePool = preparePool; + } + + @Override + public boolean preparePool() { + return preparePool; } @Override diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java index c9fa6c242e..2c50c3e7bc 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java @@ -32,10 +32,12 @@ * @author Mark Paluch * @author Christoph Strobl * @author Yanming Zhou + * @author Asmir Mustafic * @since 2.0 */ public interface LettucePoolingClientConfiguration extends LettuceClientConfiguration { + boolean preparePool(); /** * @return the {@link GenericObjectPoolConfig}. Never {@literal null}. */ @@ -92,6 +94,7 @@ static LettucePoolingClientConfiguration defaultConfiguration() { class LettucePoolingClientConfigurationBuilder extends LettuceClientConfigurationBuilder { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + boolean preparePool = false; LettucePoolingClientConfigurationBuilder() { super(); @@ -125,6 +128,12 @@ public LettucePoolingClientConfigurationBuilder commandTimeout(Duration timeout) return this; } + public LettucePoolingClientConfigurationBuilder preparePool(boolean preparePool) { + + this.preparePool = preparePool; + return this; + } + @Override public LettucePoolingClientConfigurationBuilder shutdownTimeout(Duration shutdownTimeout) { @@ -173,7 +182,7 @@ public LettucePoolingClientConfigurationBuilder poolConfig(GenericObjectPoolConf @Override public LettucePoolingClientConfiguration build() { - return new DefaultLettucePoolingClientConfiguration(super.build(), poolConfig); + return new DefaultLettucePoolingClientConfiguration(super.build(), poolConfig, preparePool); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java index 79e6b5e836..5ae577c377 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java @@ -55,6 +55,7 @@ * * @author Mark Paluch * @author Christoph Strobl + * @author Asmir Mustafic * @since 2.0 * @see #getConnection(Class) */ @@ -63,6 +64,7 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Red private static final Log log = LogFactory.getLog(LettucePoolingConnectionProvider.class); private final LettuceConnectionProvider connectionProvider; + private final LettucePoolingClientConfiguration clientConfiguration; private final GenericObjectPoolConfig poolConfig; private final Map, GenericObjectPool>> poolRef = new ConcurrentHashMap<>( 32); @@ -81,6 +83,7 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Red Assert.notNull(connectionProvider, "ConnectionProvider must not be null"); Assert.notNull(clientConfiguration, "ClientConfiguration must not be null"); + this.clientConfiguration = clientConfiguration; this.connectionProvider = connectionProvider; this.poolConfig = clientConfiguration.getPoolConfig(); this.asyncPoolConfig = CommonsPool2ConfigConverter.bounded(this.poolConfig); @@ -90,8 +93,21 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Red public > T getConnection(Class connectionType) { GenericObjectPool> pool = pools.computeIfAbsent(connectionType, poolType -> { - return ConnectionPoolSupport.createGenericObjectPool(() -> connectionProvider.getConnection(connectionType), - poolConfig, false); + + GenericObjectPool> newPool = ConnectionPoolSupport.createGenericObjectPool(() -> + connectionProvider.getConnection(connectionType), poolConfig, false); + + if (clientConfiguration.preparePool()) { + + try { + newPool.preparePool(); + + } catch (Exception ex) { + throw new PoolException("Could not prepare the pool", ex); + } + } + + return newPool; }); try { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java index ba9fd4a31a..2ec88baa7a 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java @@ -37,6 +37,7 @@ * @author Christoph Strobl * @author Longlong Zhao * @author Zhian Chen + * @author Asmir Mustafic */ class LettucePoolingClientConfigurationUnitTests { @@ -48,6 +49,7 @@ void shouldCreateEmptyConfiguration() { assertThat(configuration.getPoolConfig()).isNotNull(); assertThat(configuration.isUseSsl()).isFalse(); assertThat(configuration.isVerifyPeer()).isTrue(); + assertThat(configuration.preparePool()).isFalse(); assertThat(configuration.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(configuration.isStartTls()).isFalse(); assertThat(configuration.getClientOptions()).hasValueSatisfying(actual -> { @@ -73,6 +75,7 @@ void shouldConfigureAllProperties() { .disablePeerVerification() // .startTls().and() // .poolConfig(poolConfig) // + .preparePool(true) .clientOptions(clientOptions) // .clientResources(sharedClientResources) // .commandTimeout(Duration.ofMinutes(5)) // @@ -83,6 +86,7 @@ void shouldConfigureAllProperties() { assertThat(configuration.getPoolConfig()).isEqualTo(poolConfig); assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isFalse(); + assertThat(configuration.preparePool()).isTrue(); assertThat(configuration.getVerifyMode().equals(SslVerifyMode.NONE)); assertThat(configuration.isStartTls()).isTrue(); assertThat(configuration.getClientOptions()).contains(clientOptions); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java index ebd84f545e..45b58e1043 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java @@ -20,6 +20,7 @@ import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.api.async.RedisAsyncCommands; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,11 +28,13 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder; /** * Unit tests for {@link LettucePoolingConnectionProvider}. * * @author Mark Paluch + * @author Asmir Mustafic */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -70,4 +73,32 @@ void shouldDiscardTransactionOnReleaseOnActiveTransaction() { verify(commandsMock).discard(); } + + @Test + void shouldPrepareThePool() { + + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + poolConfig.setMinIdle(5); + poolConfig.setMaxIdle(8); + poolConfig.setMaxTotal(10); + + LettucePoolingClientConfiguration config = new LettucePoolingClientConfigurationBuilder() + .poolConfig(poolConfig) + .preparePool(true) + .build(); + + LettucePoolingConnectionProvider provider = new LettucePoolingConnectionProvider(connectionProviderMock, config); + + provider.getConnection(StatefulRedisConnection.class); + verify(connectionProviderMock, times(5)).getConnection(any()); + } + + @Test + void shouldNotPrepareThePoolByDefault() { + + LettucePoolingConnectionProvider provider = new LettucePoolingConnectionProvider(connectionProviderMock, config); + + provider.getConnection(StatefulRedisConnection.class); + verify(connectionProviderMock, times(1)).getConnection(any()); + } }