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..19eb353a86 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 @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.data.redis; import java.net.UnknownHostException; -import java.time.Duration; import org.apache.commons.pool2.impl.GenericObjectPool; import redis.clients.jedis.Jedis; @@ -27,6 +26,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; @@ -89,16 +89,11 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { } private JedisClientConfigurationBuilder applyProperties(JedisClientConfigurationBuilder builder) { - if (getProperties().isSsl()) { - builder.useSsl(); - } - if (getProperties().getTimeout() != null) { - Duration timeout = getProperties().getTimeout(); - builder.readTimeout(timeout).connectTimeout(timeout); - } - if (StringUtils.hasText(getProperties().getClientName())) { - builder.clientName(getProperties().getClientName()); - } + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(getProperties().isSsl()).whenTrue().toCall(builder::useSsl); + map.from(getProperties().getTimeout()).to(builder::readTimeout); + map.from(getProperties().getConnectTimeout()).to(builder::connectTimeout); + map.from(getProperties().getClientName()).whenHasText().to(builder::clientName); return builder; } 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..a813084f44 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,7 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { if (StringUtils.hasText(getProperties().getUrl())) { customizeConfigurationFromUrl(builder); } - builder.clientOptions(initializeClientOptionsBuilder().timeoutOptions(TimeoutOptions.enabled()).build()); + builder.clientOptions(createClientOptions()); builder.clientResources(clientResources); builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); @@ -129,6 +131,15 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { return builder; } + private ClientOptions createClientOptions() { + ClientOptions.Builder builder = initializeClientOptionsBuilder(); + Duration connectTimeout = getProperties().getConnectTimeout(); + if (connectTimeout != null) { + builder.socketOptions(SocketOptions.builder().connectTimeout(connectTimeout).build()); + } + return builder.timeoutOptions(TimeoutOptions.enabled()).build(); + } + private ClientOptions.Builder initializeClientOptionsBuilder() { if (getProperties().getCluster() != null) { ClusterClientOptions.Builder builder = ClusterClientOptions.builder(); 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..a9607fda4c 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 connectTimeout; + /** * Client name to be set on connections with CLIENT SETNAME. */ @@ -145,6 +150,14 @@ public class RedisProperties { return this.timeout; } + public Duration getConnectTimeout() { + return this.connectTimeout; + } + + public void setConnectTimeout(Duration connectTimeout) { + this.connectTimeout = connectTimeout; + } + 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..4d44b2a638 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 @@ -136,11 +136,23 @@ class RedisAutoConfigurationJedisTests { } @Test - void testRedisConfigurationWithTimeout() { - this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:100").run((context) -> { + void testRedisConfigurationWithTimeoutAndConnectTimeout() { + this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250", + "spring.redis.connect-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..b0095a94b1 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,25 @@ class RedisAutoConfigurationTests { } @Test - void testRedisConfigurationWithTimeout() { - this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:100").run((context) -> { + void testRedisConfigurationWithTimeoutAndConnectTimeout() { + this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250", + "spring.redis.connect-timeout:1000").run((context) -> { + LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class); + assertThat(cf.getHostName()).isEqualTo("foo"); + assertThat(cf.getTimeout()).isEqualTo(250); + assertThat(cf.getClientConfiguration().getClientOptions().get().getSocketOptions() + .getConnectTimeout().toMillis()).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); + assertThat(cf.getClientConfiguration().getClientOptions().get().getSocketOptions().getConnectTimeout() + .toMillis()).isEqualTo(10000); }); }