Use lb scheme to find the baseUrls for load-balancing.
Signed-off-by: Olga Maciaszek-Sharma <olga.maciaszek-sharma@broadcom.com>
This commit is contained in:
@@ -204,7 +204,7 @@ WARNING: If using any of the Service Discovery-backed suppliers, adding this hea
|
||||
from the Service Registry.
|
||||
|
||||
TIP: The `HealthCheckServiceInstanceListSupplier` relies on having updated instances provided by a delegate flux. In the rare cases when you want to use a delegate that does not refresh the instances, even though the list of instances may change (such as the `DiscoveryClientServiceInstanceListSupplier` provided by us), you can set `spring.cloud.loadbalancer.health-check.refetch-instances` to `true` to have the instance list refreshed by the `HealthCheckServiceInstanceListSupplier`. You can then also adjust the refretch intervals by modifying the value of `spring.cloud.loadbalancer.health-check.refetch-instances-interval` and opt to disable the additional healthcheck repetitions by setting `spring.cloud.loadbalancer.health-check.repeat-health-check` to `false` as every instances refetch
|
||||
will also trigger a healthcheck.
|
||||
will also trigger a healthcheck.
|
||||
|
||||
`HealthCheckServiceInstanceListSupplier` uses properties prefixed with
|
||||
`spring.cloud.loadbalancer.health-check`. You can set the `initialDelay` and `interval`
|
||||
@@ -561,7 +561,7 @@ Since `5.0.0`, Spring Cloud LoadBalancer supports https://docs.spring.io/spring-
|
||||
For each Interface Client group, if the group `baseUrl` (defined under the
|
||||
`spring.http.client.service.group.[groupName].base-url` property) is `null`, a `serviceId`-based URL for load-balancing is set up as the `baseUrl`, with `serviceId` resolved from the Interface Client `groupName`.
|
||||
|
||||
If the group `baseUrl` is `null` or it is already a `serviceId`-based URL, a
|
||||
If the group `baseUrl` is `null` or its scheme is set to `lb`, a
|
||||
`DeferringLoadBalancerInterceptor` instance is picked from the application context for blocking scenarios, and a `DeferringLoadBalancerExchangeFilterFunction` instance for reactive scenarios, and is added to the group's `RestClient.Builder` or `WebClient.Builder` if available, allowing for the requests to be load-balanced.
|
||||
|
||||
For example, in an app with the following Interface Clients configuration:
|
||||
@@ -579,10 +579,11 @@ public class HttpVerificationClientApplication {
|
||||
}
|
||||
----
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is not set, it will be automatically set to `http://verificationClient`. The default scheme (`http`) is used initially; however, if a secure `ServiceInstance` is selected through load-balancing, it will be changed to `https`.
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is not set, it will be automatically set to `http://verificationClient`.
|
||||
The default scheme (`http`) is used initially; however, if a secure `ServiceInstance` is selected through load-balancing, it will be changed to `https`.
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that uses the `groupName` / `serviceId` as the host (for example, `https://verificationClient/path`), it will be left unchanged. In both of these cases, either a `DeferringLoadBalancerInterceptor` or `DeferringLoadBalancerExchangeFilterFunction` will be added to the group's client builder, enabling the requests to be load-balanced.
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that has the `lb` scheme, (for example, `lb://verificationClient/path`), it will be used with `http` being initially set as the default scheme.
|
||||
If a secure `ServiceInstance` is selected through load-balancing, the scheme will be changed to `https`.
|
||||
In both of these cases, either a `DeferringLoadBalancerInterceptor` or `DeferringLoadBalancerExchangeFilterFunction` will be added to the group's client builder, enabling the requests to be load-balanced.
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that does not have `verificationClient` as the host (for example, `http://someOtherHost/path`), no load-balancer integration will be applied.
|
||||
|
||||
TIP: To use a different default scheme instead of `http` (for example, `ws`, which would be converted to `wss` if a secure `ServiceInstance` is selected), set the `spring.http.client.service.group.verificationClient.base-url` property with the desired scheme.
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that does not have the scheme set to `lb`, (for example, `lb://verificationClient/path`), no load-balancer integration will be applied.
|
||||
|
||||
@@ -25,9 +25,10 @@ import org.springframework.boot.autoconfigure.http.client.service.HttpClientServ
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.DEFAULT_SCHEME;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.constructInterfaceClientsBaseUrl;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.isServiceIdUrl;
|
||||
|
||||
/**
|
||||
* Load-balancer-specific {@link RestClientHttpServiceGroupConfigurer} implementation. If
|
||||
@@ -71,12 +72,16 @@ public class LoadBalancerRestClientHttpServiceGroupConfigurer implements RestCli
|
||||
groups.configureClient((group, builder) -> {
|
||||
String groupName = group.name();
|
||||
HttpClientServiceProperties.Group groupProperties = clientServiceProperties.getGroup().get(groupName);
|
||||
if (groupProperties == null || groupProperties.getBaseUrl() == null) {
|
||||
String baseUrlString = groupProperties == null ? null : groupProperties.getBaseUrl();
|
||||
URI existingBaseUrl = baseUrlString == null ? null : URI.create(baseUrlString);
|
||||
if (existingBaseUrl == null) {
|
||||
URI baseUrl = constructBaseUrl(groupName);
|
||||
builder.baseUrl(baseUrl);
|
||||
builder.requestInterceptor(loadBalancerInterceptor);
|
||||
}
|
||||
else if (isServiceIdUrl(groupProperties.getBaseUrl(), groupName)) {
|
||||
else if ("lb".equalsIgnoreCase(existingBaseUrl.getScheme())) {
|
||||
URI baseUrl = UriComponentsBuilder.fromUri(existingBaseUrl).scheme(DEFAULT_SCHEME).build().toUri();
|
||||
builder.baseUrl(baseUrl);
|
||||
builder.requestInterceptor(loadBalancerInterceptor);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,15 +17,11 @@
|
||||
package org.springframework.cloud.client.loadbalancer;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@@ -39,16 +35,17 @@ public final class LoadBalancerUriTools {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(LoadBalancerUriTools.class);
|
||||
|
||||
private static final String PERCENTAGE_SIGN = "%";
|
||||
|
||||
private static final String DEFAULT_SCHEME = "http";
|
||||
|
||||
private static final String DEFAULT_SECURE_SCHEME = "https";
|
||||
|
||||
private static final Map<String, String> INSECURE_SCHEME_MAPPINGS;
|
||||
|
||||
/**
|
||||
* Default scheme.
|
||||
*/
|
||||
public static final String DEFAULT_SCHEME = "http";
|
||||
|
||||
static {
|
||||
INSECURE_SCHEME_MAPPINGS = new HashMap<>();
|
||||
INSECURE_SCHEME_MAPPINGS.put(DEFAULT_SCHEME, DEFAULT_SECURE_SCHEME);
|
||||
@@ -125,24 +122,4 @@ public final class LoadBalancerUriTools {
|
||||
return UriComponentsBuilder.newInstance().scheme(DEFAULT_SCHEME).host(groupName).encode().build().toUri();
|
||||
}
|
||||
|
||||
public static boolean isServiceIdUrl(String baseUrlString, String serviceId) {
|
||||
if (serviceId == null) {
|
||||
return false;
|
||||
}
|
||||
if (baseUrlString == null) {
|
||||
return false;
|
||||
}
|
||||
URI baseUrl;
|
||||
try {
|
||||
baseUrl = new URI(baseUrlString);
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
if (LOG.isErrorEnabled()) {
|
||||
LOG.error("Incorrect baseUrl String syntax", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return serviceId.equals(baseUrl.getHost());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.DEFAULT_SCHEME;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.constructInterfaceClientsBaseUrl;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.isServiceIdUrl;
|
||||
|
||||
/**
|
||||
* Load-balancer-specific {@link WebClientHttpServiceGroupConfigurer} implementation. If
|
||||
@@ -73,12 +74,19 @@ public class LoadBalancerWebClientHttpServiceGroupConfigurer implements WebClien
|
||||
String groupName = group.name();
|
||||
ReactiveHttpClientServiceProperties.Group groupProperties = clientServiceProperties.getGroup()
|
||||
.get(groupName);
|
||||
if (groupProperties == null || groupProperties.getBaseUrl() == null) {
|
||||
String baseUrlString = groupProperties == null ? null : groupProperties.getBaseUrl();
|
||||
URI existingBaseUrl = baseUrlString == null ? null : URI.create(baseUrlString);
|
||||
if (existingBaseUrl == null) {
|
||||
URI baseUrl = constructBaseUrl(groupName);
|
||||
builder.baseUrl(String.valueOf(baseUrl));
|
||||
builder.filter(loadBalancerFilterFunction);
|
||||
}
|
||||
else if (isServiceIdUrl(groupProperties.getBaseUrl(), groupName)) {
|
||||
else if ("lb".equalsIgnoreCase(existingBaseUrl.getScheme())) {
|
||||
String baseUrl = UriComponentsBuilder.fromUri(existingBaseUrl)
|
||||
.scheme(DEFAULT_SCHEME)
|
||||
.build()
|
||||
.toUriString();
|
||||
builder.baseUrl(baseUrl);
|
||||
builder.filter(loadBalancerFilterFunction);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -72,9 +72,9 @@ class LoadBalancerRestClientHttpServiceGroupConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlIsServiceIdUrl() {
|
||||
void shouldAddInterceptorWhenBaseUrlHasLbScheme() {
|
||||
Group group = new Group();
|
||||
group.setBaseUrl("https://" + GROUP_NAME + "/path");
|
||||
group.setBaseUrl("lb://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer configurer = new LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
interceptorProvider, clientServiceProperties);
|
||||
@@ -89,9 +89,9 @@ class LoadBalancerRestClientHttpServiceGroupConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAddInterceptorWhenBaseUrlIsNotServiceIdUrl() {
|
||||
void shouldNotAddInterceptorWhenBaseDoesNotHaveLbScheme() {
|
||||
Group group = new Group();
|
||||
group.setBaseUrl("https://some-other-service/path");
|
||||
group.setBaseUrl("http://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer configurer = new LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
interceptorProvider, clientServiceProperties);
|
||||
|
||||
@@ -19,19 +19,13 @@ package org.springframework.cloud.client.loadbalancer;
|
||||
import java.net.URI;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.web.util.InvalidUrlException;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link LoadBalancerUriTools}.
|
||||
@@ -189,29 +183,6 @@ class LoadBalancerUriToolsTests {
|
||||
assertThat(reconstructed.getPort()).isEqualTo(serviceInstance.getPort());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{index} => url={0}, serviceId={1}, expected={2}")
|
||||
@MethodSource("provideUrlAndServiceIdForIsServiceIdUrl")
|
||||
void verifyServiceIdUrl(String url, String serviceId, boolean expected) {
|
||||
assertThat(LoadBalancerUriTools.isServiceIdUrl(url, serviceId)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyServiceIdIncorrectUrl() {
|
||||
assertThatExceptionOfType(InvalidUrlException.class).isThrownBy(() -> {
|
||||
URI baseUrl = UriComponentsBuilder.fromUriString("https://:testService/xxx").build().toUri();
|
||||
|
||||
LoadBalancerUriTools.isServiceIdUrl(String.valueOf(baseUrl), null);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static Stream<Arguments> provideUrlAndServiceIdForIsServiceIdUrl() {
|
||||
return Stream.of(org.junit.jupiter.params.provider.Arguments.of("https://testService/xxx", "testService", true),
|
||||
org.junit.jupiter.params.provider.Arguments.of("https://test/xxx", "testService", false),
|
||||
org.junit.jupiter.params.provider.Arguments.of("https://testService/xxx", null, false),
|
||||
org.junit.jupiter.params.provider.Arguments.of(null, "testService", false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestServiceInstance implements ServiceInstance {
|
||||
|
||||
@@ -73,9 +73,9 @@ class LoadBalancerWebClientHttpServiceGroupConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlIsServiceIdUrl() {
|
||||
void shouldAddInterceptorWhenBaseUrlHasLbScheme() {
|
||||
ReactiveHttpClientServiceProperties.Group group = new ReactiveHttpClientServiceProperties.Group();
|
||||
group.setBaseUrl("https://" + GROUP_NAME + "/path");
|
||||
group.setBaseUrl("lb://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer configurer = new LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
exchangeFilterFunctionProvider, clientServiceProperties);
|
||||
@@ -90,9 +90,9 @@ class LoadBalancerWebClientHttpServiceGroupConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAddInterceptorWhenBaseUrlIsNotServiceIdUrl() {
|
||||
void shouldNotAddInterceptorWhenBaseDoesNotHaveLbScheme() {
|
||||
ReactiveHttpClientServiceProperties.Group group = new ReactiveHttpClientServiceProperties.Group();
|
||||
group.setBaseUrl("https://some-other-service/path");
|
||||
group.setBaseUrl("https://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer configurer = new LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
exchangeFilterFunctionProvider, clientServiceProperties);
|
||||
|
||||
Reference in New Issue
Block a user