diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java index 91331a5e9d..af47306b90 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java @@ -92,9 +92,13 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { if (getProperties().isSsl()) { builder.useSsl(); } - if (getProperties().getTimeout() != null) { - Duration timeout = getProperties().getTimeout(); - builder.readTimeout(timeout).connectTimeout(timeout); + Duration connectionTimeout = getProperties().getConnectionTimeout(); + if (connectionTimeout != null) { + builder.connectTimeout(connectionTimeout); + } + Duration timeout = getProperties().getTimeout(); + if (timeout != null) { + builder.readTimeout(timeout); } if (StringUtils.hasText(getProperties().getClientName())) { builder.clientName(getProperties().getClientName()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index f49acdbfe9..b2aafb3027 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -17,9 +17,11 @@ package org.springframework.boot.autoconfigure.data.redis; import java.net.UnknownHostException; +import java.time.Duration; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisClient; +import io.lettuce.core.SocketOptions; import io.lettuce.core.TimeoutOptions; import io.lettuce.core.cluster.ClusterClientOptions; import io.lettuce.core.cluster.ClusterTopologyRefreshOptions; @@ -96,7 +98,15 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { if (StringUtils.hasText(getProperties().getUrl())) { customizeConfigurationFromUrl(builder); } - builder.clientOptions(initializeClientOptionsBuilder().timeoutOptions(TimeoutOptions.enabled()).build()); + + ClientOptions.Builder clientOptionsBuilder = initializeClientOptionsBuilder(); + Duration connectionTimeout = getProperties().getConnectionTimeout(); + if (connectionTimeout != null) { + SocketOptions socketOptions = SocketOptions.builder().connectTimeout(connectionTimeout).build(); + clientOptionsBuilder.socketOptions(socketOptions); + } + builder.clientOptions(clientOptionsBuilder.timeoutOptions(TimeoutOptions.enabled()).build()); + builder.clientResources(clientResources); builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); @@ -114,8 +124,9 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { if (getProperties().isSsl()) { builder.useSsl(); } - if (getProperties().getTimeout() != null) { - builder.commandTimeout(getProperties().getTimeout()); + Duration timeout = getProperties().getTimeout(); + if (timeout != null) { + builder.commandTimeout(timeout); } if (getProperties().getLettuce() != null) { RedisProperties.Lettuce lettuce = getProperties().getLettuce(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java index d8c12b6148..0e665f19b2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java @@ -67,10 +67,15 @@ public class RedisProperties { private boolean ssl; /** - * Connection timeout. + * Read timeout. */ private Duration timeout; + /** + * Connection timeout. + */ + private Duration connectionTimeout; + /** * Client name to be set on connections with CLIENT SETNAME. */ @@ -145,6 +150,14 @@ public class RedisProperties { return this.timeout; } + public Duration getConnectionTimeout() { + return this.connectionTimeout; + } + + public void setConnectionTimeout(Duration connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + public String getClientName() { return this.clientName; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java index 3e23b540cf..f4e3cf6085 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java @@ -16,13 +16,14 @@ package org.springframework.boot.autoconfigure.data.redis; +import io.lettuce.core.RedisClient; import org.junit.jupiter.api.Test; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.boot.testsupport.classpath.ClassPathExclusions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -37,11 +38,11 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Mark Paluch * @author Stephane Nicoll */ -@ClassPathExclusions("lettuce-core-*.jar") class RedisAutoConfigurationJedisTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader(RedisClient.class)); @Test void connectionFactoryDefaultsToJedis() { @@ -136,11 +137,23 @@ class RedisAutoConfigurationJedisTests { } @Test - void testRedisConfigurationWithTimeout() { - this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:100").run((context) -> { + void testRedisConfigurationWithTimeoutAndConnectionTimeout() { + this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250", + "spring.redis.connection-timeout:1000").run((context) -> { + JedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class); + assertThat(cf.getHostName()).isEqualTo("foo"); + assertThat(cf.getTimeout()).isEqualTo(250); + assertThat(cf.getClientConfiguration().getConnectTimeout().toMillis()).isEqualTo(1000); + }); + } + + @Test + void testRedisConfigurationWithDefaultTimeouts() { + this.contextRunner.withPropertyValues("spring.redis.host:foo").run((context) -> { JedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class); assertThat(cf.getHostName()).isEqualTo("foo"); - assertThat(cf.getTimeout()).isEqualTo(100); + assertThat(cf.getTimeout()).isEqualTo(2000); + assertThat(cf.getClientConfiguration().getConnectTimeout().toMillis()).isEqualTo(2000); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 7e9a474ab0..835ad98755 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -168,11 +168,27 @@ class RedisAutoConfigurationTests { } @Test - void testRedisConfigurationWithTimeout() { - this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:100").run((context) -> { + void testRedisConfigurationWithTimeoutAndConnectionTimeout() { + this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250", + "spring.redis.connection-timeout:1000").run((context) -> { + LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class); + assertThat(cf.getHostName()).isEqualTo("foo"); + assertThat(cf.getTimeout()).isEqualTo(250); + long actualConnectionTimeout = cf.getClientConfiguration().getClientOptions().get() + .getSocketOptions().getConnectTimeout().toMillis(); + assertThat(actualConnectionTimeout).isEqualTo(1000); + }); + } + + @Test + void testRedisConfigurationWithDefaultTimeouts() { + this.contextRunner.withPropertyValues("spring.redis.host:foo").run((context) -> { LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class); assertThat(cf.getHostName()).isEqualTo("foo"); - assertThat(cf.getTimeout()).isEqualTo(100); + assertThat(cf.getTimeout()).isEqualTo(60000); + long actualConnectionTimeout = cf.getClientConfiguration().getClientOptions().get().getSocketOptions() + .getConnectTimeout().toMillis(); + assertThat(actualConnectionTimeout).isEqualTo(10000); }); }