From 5bacb325579805a82b7a2253403e97a62836b50c Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Fri, 15 Feb 2019 13:49:09 +0200 Subject: [PATCH 1/2] Allow to configure the Elasticsearch rest client timeouts See gh-15965 --- .../rest/RestClientAutoConfiguration.java | 10 ++++++ .../rest/RestClientProperties.java | 29 ++++++++++++++- .../RestClientAutoConfigurationTests.java | 36 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index f6ae06c18e..586c292cf9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; +import java.time.Duration; + import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; @@ -68,6 +70,14 @@ public class RestClientAutoConfiguration { builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder .setDefaultCredentialsProvider(credentialsProvider)); }); + builder.setRequestConfigCallback((requestConfigBuilder) -> { + map.from(properties::getConnectionTimeout).whenNonNull() + .as(Duration::toMillis).asInt(Math::toIntExact) + .to(requestConfigBuilder::setConnectTimeout); + map.from(properties::getReadTimeout).whenNonNull().as(Duration::toMillis) + .asInt(Math::toIntExact).to(requestConfigBuilder::setSocketTimeout); + return requestConfigBuilder; + }); builderCustomizers.orderedStream() .forEach((customizer) -> customizer.customize(builder)); return builder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java index fe99730146..c4884e1340 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -47,6 +48,16 @@ public class RestClientProperties { */ private String password; + /** + * Connection timeout. + */ + private Duration connectionTimeout = Duration.ofSeconds(1); + + /** + * Read timeout. + */ + private Duration readTimeout = Duration.ofSeconds(30); + public List getUris() { return this.uris; } @@ -71,4 +82,20 @@ public class RestClientProperties { this.password = password; } + public Duration getConnectionTimeout() { + return this.connectionTimeout; + } + + public void setConnectionTimeout(Duration connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public Duration getReadTimeout() { + return this.readTimeout; + } + + public void setReadTimeout(Duration readTimeout) { + this.readTimeout = readTimeout; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java index 86a8d4e544..1bbc1ad9eb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; +import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -23,6 +24,7 @@ import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.junit.ClassRule; import org.junit.Test; @@ -32,6 +34,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -74,6 +77,30 @@ public class RestClientAutoConfigurationTests { }); } + @Test + public void defaultTimeoutsShouldBeConfigured() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(RestClient.class); + RestClient restClient = context.getBean(RestClient.class); + assertTimeouts(restClient, + Duration.ofMillis(RestClientBuilder.DEFAULT_CONNECT_TIMEOUT_MILLIS), Duration.ofMillis(RestClientBuilder.DEFAULT_SOCKET_TIMEOUT_MILLIS) + ); + }); + } + + @Test + public void timeoutsCanBeConfigured() { + this.contextRunner + .withPropertyValues("spring.elasticsearch.rest.connection-timeout=15s", + "spring.elasticsearch.rest.read-timeout=1m") + .run((context) -> { + assertThat(context).hasSingleBean(RestClient.class); + RestClient restClient = context.getBean(RestClient.class); + assertTimeouts(restClient, Duration.ofSeconds(15), Duration.ofMinutes(1) + ); + }); + } + @Test public void restClientCanQueryElasticsearchNode() { this.contextRunner @@ -94,6 +121,15 @@ public class RestClientAutoConfigurationTests { }); } + private static void assertTimeouts(RestClient restClient, Duration connectTimeout, Duration readTimeout) { + Object client = ReflectionTestUtils.getField(restClient, "client"); + Object config = ReflectionTestUtils.getField(client, "defaultConfig"); + assertThat(config).hasFieldOrPropertyWithValue("socketTimeout", + Math.toIntExact(readTimeout.toMillis())); + assertThat(config).hasFieldOrPropertyWithValue("connectTimeout", + Math.toIntExact(connectTimeout.toMillis())); + } + @Configuration(proxyBeanMethods = false) static class CustomRestClientConfiguration { From 2cfcd2690eb22dfc59b979e3a74b8ea858e3b94e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 18 Apr 2019 11:14:27 +0200 Subject: [PATCH 2/2] Polish "Allow to configure the Elasticsearch rest client timeouts" Closes gh-15965 --- .../RestClientAutoConfigurationTests.java | 31 ++++++++++--------- .../main/asciidoc/spring-boot-features.adoc | 1 + 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java index 1bbc1ad9eb..ef47b22b7d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -78,29 +78,39 @@ public class RestClientAutoConfigurationTests { } @Test - public void defaultTimeoutsShouldBeConfigured() { + public void configureWithNoTimeoutsApplyDefaults() { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(RestClient.class); RestClient restClient = context.getBean(RestClient.class); assertTimeouts(restClient, - Duration.ofMillis(RestClientBuilder.DEFAULT_CONNECT_TIMEOUT_MILLIS), Duration.ofMillis(RestClientBuilder.DEFAULT_SOCKET_TIMEOUT_MILLIS) - ); + Duration.ofMillis(RestClientBuilder.DEFAULT_CONNECT_TIMEOUT_MILLIS), + Duration.ofMillis(RestClientBuilder.DEFAULT_SOCKET_TIMEOUT_MILLIS)); }); } @Test - public void timeoutsCanBeConfigured() { + public void configureWithCustomTimeouts() { this.contextRunner .withPropertyValues("spring.elasticsearch.rest.connection-timeout=15s", "spring.elasticsearch.rest.read-timeout=1m") .run((context) -> { assertThat(context).hasSingleBean(RestClient.class); RestClient restClient = context.getBean(RestClient.class); - assertTimeouts(restClient, Duration.ofSeconds(15), Duration.ofMinutes(1) - ); + assertTimeouts(restClient, Duration.ofSeconds(15), + Duration.ofMinutes(1)); }); } + private static void assertTimeouts(RestClient restClient, Duration connectTimeout, + Duration readTimeout) { + Object client = ReflectionTestUtils.getField(restClient, "client"); + Object config = ReflectionTestUtils.getField(client, "defaultConfig"); + assertThat(config).hasFieldOrPropertyWithValue("socketTimeout", + Math.toIntExact(readTimeout.toMillis())); + assertThat(config).hasFieldOrPropertyWithValue("connectTimeout", + Math.toIntExact(connectTimeout.toMillis())); + } + @Test public void restClientCanQueryElasticsearchNode() { this.contextRunner @@ -121,15 +131,6 @@ public class RestClientAutoConfigurationTests { }); } - private static void assertTimeouts(RestClient restClient, Duration connectTimeout, Duration readTimeout) { - Object client = ReflectionTestUtils.getField(restClient, "client"); - Object config = ReflectionTestUtils.getField(client, "defaultConfig"); - assertThat(config).hasFieldOrPropertyWithValue("socketTimeout", - Math.toIntExact(readTimeout.toMillis())); - assertThat(config).hasFieldOrPropertyWithValue("connectTimeout", - Math.toIntExact(connectTimeout.toMillis())); - } - @Configuration(proxyBeanMethods = false) static class CustomRestClientConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 9e1adc7492..c289788c68 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4805,6 +4805,7 @@ You can further tune how `RestClient` is configured, as shown in the following e [source,properties,indent=0] ---- spring.elasticsearch.rest.uris=https://search.example.com:9200 + spring.elasticsearch.rest.read-timeout=10s spring.elasticsearch.rest.username=user spring.elasticsearch.rest.password=secret ----