@LoadBalanced RestClient (#1294)
This commit is contained in:
committed by
GitHub
parent
42ba0eef31
commit
dd47ca6c29
@@ -48,6 +48,7 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@@ -188,6 +189,16 @@ public class LoadBalancerClientConfiguration {
|
||||
.build(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean({ DiscoveryClient.class, RestClient.class })
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(HealthCheckConfigurationCondition.class)
|
||||
public ServiceInstanceListSupplier healthCheckRestClientDiscoveryClientServiceInstanceListSupplier(
|
||||
ConfigurableApplicationContext context) {
|
||||
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
|
||||
.withBlockingRestClientHealthChecks().build(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(DiscoveryClient.class)
|
||||
@ConditionalOnMissingBean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2023 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.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.BlockingRestClassesPresentCondition;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
@@ -35,9 +36,9 @@ import org.springframework.cloud.loadbalancer.blocking.retry.BlockingLoadBalance
|
||||
import org.springframework.cloud.loadbalancer.core.LoadBalancerServiceInstanceCookieTransformer;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* An autoconfiguration for {@link BlockingLoadBalancerClient}.
|
||||
@@ -50,7 +51,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
@LoadBalancerClients
|
||||
@AutoConfigureAfter(LoadBalancerAutoConfiguration.class)
|
||||
@AutoConfigureBefore({ org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration.class })
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
@Conditional(BlockingRestClassesPresentCondition.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class BlockingLoadBalancerClientAutoConfiguration {
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -203,6 +204,21 @@ public final class ServiceInstanceListSupplierBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HealthCheckServiceInstanceListSupplier} that uses user-provided
|
||||
* {@link RestClient} instance to the {@link ServiceInstanceListSupplier} hierarchy.
|
||||
* @return the {@link ServiceInstanceListSupplierBuilder} object
|
||||
*/
|
||||
public ServiceInstanceListSupplierBuilder withBlockingRestClientHealthChecks() {
|
||||
DelegateCreator creator = (context, delegate) -> {
|
||||
RestClient restClient = context.getBean(RestClient.class);
|
||||
LoadBalancerClientFactory loadBalancerClientFactory = context.getBean(LoadBalancerClientFactory.class);
|
||||
return blockingHealthCheckServiceInstanceListSupplier(restClient, delegate, loadBalancerClientFactory);
|
||||
};
|
||||
this.creators.add(creator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HealthCheckServiceInstanceListSupplier} that uses user-provided
|
||||
* {@link RestTemplate} instance to the {@link ServiceInstanceListSupplier} hierarchy.
|
||||
@@ -218,6 +234,21 @@ public final class ServiceInstanceListSupplierBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HealthCheckServiceInstanceListSupplier} that uses user-provided
|
||||
* {@link RestClient} instance to the {@link ServiceInstanceListSupplier} hierarchy.
|
||||
* @param restClient a user-provided {@link RestClient} instance
|
||||
* @return the {@link ServiceInstanceListSupplierBuilder} object
|
||||
*/
|
||||
public ServiceInstanceListSupplierBuilder withBlockingHealthChecks(RestClient restClient) {
|
||||
DelegateCreator creator = (context, delegate) -> {
|
||||
LoadBalancerClientFactory loadBalancerClientFactory = context.getBean(LoadBalancerClientFactory.class);
|
||||
return blockingHealthCheckServiceInstanceListSupplier(restClient, delegate, loadBalancerClientFactory);
|
||||
};
|
||||
this.creators.add(creator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link ZonePreferenceServiceInstanceListSupplier} to the
|
||||
* {@link ServiceInstanceListSupplier} hierarchy.
|
||||
@@ -371,6 +402,22 @@ public final class ServiceInstanceListSupplierBuilder {
|
||||
}));
|
||||
}
|
||||
|
||||
private ServiceInstanceListSupplier blockingHealthCheckServiceInstanceListSupplier(RestClient restClient,
|
||||
ServiceInstanceListSupplier delegate, LoadBalancerClientFactory loadBalancerClientFactory) {
|
||||
return new HealthCheckServiceInstanceListSupplier(delegate, loadBalancerClientFactory,
|
||||
(serviceInstance, healthCheckPath) -> Mono.defer(() -> {
|
||||
URI uri = UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build()
|
||||
.toUri();
|
||||
try {
|
||||
return Mono.just(HttpStatus.OK
|
||||
.equals(restClient.get().uri(uri).retrieve().toBodilessEntity().getStatusCode()));
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
return Mono.just(false);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
static String getUri(ServiceInstance serviceInstance, String healthCheckPath) {
|
||||
if (StringUtils.hasText(healthCheckPath)) {
|
||||
String path = healthCheckPath.startsWith("/") ? healthCheckPath : "/" + healthCheckPath;
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.loadbalancer.annotation;
|
||||
|
||||
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.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
@@ -38,6 +43,7 @@ import org.springframework.cloud.loadbalancer.core.ZonePreferenceServiceInstance
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@@ -191,9 +197,10 @@ class LoadBalancerClientConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstantiateBlockingHealthCheckServiceInstanceListSupplier() {
|
||||
blockingDiscoveryClientRunner.withUserConfiguration(RestTemplateTestConfig.class)
|
||||
@ParameterizedTest
|
||||
@MethodSource("blockingConfigurations")
|
||||
void shouldInstantiateBlockingHealthCheckServiceInstanceListSupplier(Class<?> configurationClass) {
|
||||
blockingDiscoveryClientRunner.withUserConfiguration(configurationClass)
|
||||
.withPropertyValues("spring.cloud.loadbalancer.configurations=health-check").run(context -> {
|
||||
ServiceInstanceListSupplier supplier = context.getBean(ServiceInstanceListSupplier.class);
|
||||
then(supplier).isInstanceOf(HealthCheckServiceInstanceListSupplier.class);
|
||||
@@ -204,8 +211,8 @@ class LoadBalancerClientConfigurationTests {
|
||||
|
||||
@Test
|
||||
void shouldInstantiateBlockingWeightedServiceInstanceListSupplier() {
|
||||
blockingDiscoveryClientRunner.withUserConfiguration(RestTemplateTestConfig.class)
|
||||
.withPropertyValues("spring.cloud.loadbalancer.configurations=weighted").run(context -> {
|
||||
blockingDiscoveryClientRunner.withPropertyValues("spring.cloud.loadbalancer.configurations=weighted")
|
||||
.run(context -> {
|
||||
ServiceInstanceListSupplier supplier = context.getBean(ServiceInstanceListSupplier.class);
|
||||
then(supplier).isInstanceOf(WeightedServiceInstanceListSupplier.class);
|
||||
ServiceInstanceListSupplier delegate = ((DelegatingServiceInstanceListSupplier) supplier)
|
||||
@@ -216,6 +223,11 @@ class LoadBalancerClientConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
private static Stream<Arguments> blockingConfigurations() {
|
||||
return Stream.of(Arguments.of(RestTemplateTestConfig.class), Arguments.of(RestClientTestConfig.class),
|
||||
Arguments.of(RestTemplateAndRestClientConfig.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestConfig {
|
||||
|
||||
@@ -237,4 +249,29 @@ class LoadBalancerClientConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class RestClientTestConfig {
|
||||
|
||||
@Bean
|
||||
RestClient restClient() {
|
||||
return RestClient.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class RestTemplateAndRestClientConfig {
|
||||
|
||||
@Bean
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
RestClient restClient() {
|
||||
return RestClient.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2023 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.
|
||||
@@ -23,6 +23,7 @@ import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -48,7 +49,7 @@ class BlockingLoadBalancerClientAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void worksWithoutSpringWeb() {
|
||||
applicationContextRunner.withClassLoader(new FilteredClassLoader(RestTemplate.class))
|
||||
applicationContextRunner.withClassLoader(new FilteredClassLoader(RestTemplate.class, RestClient.class))
|
||||
.run(context -> assertThat(context).doesNotHaveBean(BlockingLoadBalancerClient.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2023 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.
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.util.Lists;
|
||||
@@ -29,6 +30,9 @@ import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.mockito.Mockito;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -47,6 +51,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@@ -79,10 +84,6 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private final WebClient webClient = WebClient.create();
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
private LoadBalancerProperties properties;
|
||||
|
||||
private HealthCheckServiceInstanceListSupplier listSupplier;
|
||||
@@ -109,7 +110,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
false);
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction(webClient));
|
||||
buildLoadBalancerClientFactory(serviceId, properties), webClientHealthCheckFunction());
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
@@ -151,15 +152,17 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Test
|
||||
void shouldCheckInstanceWithProvidedHealthCheckPathWithRestTemplate() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("healthCheckFunctions")
|
||||
void shouldCheckInstanceWithProvidedHealthCheckPath(
|
||||
BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunction) {
|
||||
String serviceId = "ignored-service";
|
||||
properties.getHealthCheck().getPath().put("ignored-service", "/health");
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1", serviceId, "127.0.0.1", port,
|
||||
false);
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction(restTemplate));
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction);
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
@@ -167,46 +170,16 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Test
|
||||
void shouldCheckInstanceWithDefaultHealthCheckPath() {
|
||||
String serviceId = "ignored-service";
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1", serviceId, "127.0.0.1", port,
|
||||
false);
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction(webClient));
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
assertThat(alive).isTrue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Test
|
||||
void shouldReturnFalseIfEndpointNotFound() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("healthCheckFunctions")
|
||||
void shouldReturnFalseIfEndpointNotFound(BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunction) {
|
||||
String serviceId = "ignored-service";
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1", serviceId, "127.0.0.1", port,
|
||||
false);
|
||||
properties.getHealthCheck().getPath().put(serviceId, "/test");
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction(webClient));
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
assertThat(alive).isFalse();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Test
|
||||
void shouldReturnFalseIfEndpointNotFoundWithRestTemplate() {
|
||||
String serviceId = "ignored-service";
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1", serviceId, "127.0.0.1", port,
|
||||
false);
|
||||
properties.getHealthCheck().getPath().put(serviceId, "/test");
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction(restTemplate));
|
||||
buildLoadBalancerClientFactory(serviceId, properties), healthCheckFunction);
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
@@ -232,7 +205,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.doReturn(Mono.just(false)).when(mock).isAlive(serviceInstance2);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -263,7 +236,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.doReturn(Mono.just(true)).when(mock).isAlive(serviceInstance2);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -296,7 +269,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.doReturn(Mono.just(true)).when(mock).isAlive(serviceInstance2);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -327,7 +300,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.doReturn(Mono.error(new RuntimeException("boom"))).when(mock).isAlive(serviceInstance2);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -353,7 +326,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(delegate.getServiceId()).thenReturn(SERVICE_ID);
|
||||
Mockito.when(delegate.get()).thenReturn(Flux.just(Lists.list(serviceInstance1, serviceInstance2)));
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
if (serviceInstance == serviceInstance1) {
|
||||
@@ -381,7 +354,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(delegate.getServiceId()).thenReturn(SERVICE_ID);
|
||||
Mockito.when(delegate.get()).thenReturn(Flux.just(Lists.list(serviceInstance1)));
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return Mono.just(true);
|
||||
@@ -414,7 +387,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.doReturn(Mono.error(new RuntimeException("boom"))).when(mock).isAlive(serviceInstance2);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -443,7 +416,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(mock.isAlive(serviceInstance1)).thenReturn(Mono.never(), Mono.just(true));
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return mock.isAlive(serviceInstance);
|
||||
@@ -475,7 +448,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(delegate.get()).thenReturn(instances);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return Mono.just(true);
|
||||
@@ -510,7 +483,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(delegate.get()).thenReturn(instances);
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return Mono.just(true);
|
||||
@@ -543,7 +516,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
when(delegate.get()).thenReturn(Flux.just(Collections.singletonList(serviceInstance1)))
|
||||
.thenReturn(Flux.just(Collections.singletonList(serviceInstance2)));
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return Mono.just(true);
|
||||
@@ -572,7 +545,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
when(delegate.getServiceId()).thenReturn(SERVICE_ID);
|
||||
when(delegate.get()).thenReturn(Flux.just(Collections.singletonList(serviceInstance1)))
|
||||
.thenReturn(Flux.just(Collections.singletonList(serviceInstance2)));
|
||||
BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunc = healthCheckFunction(webClient);
|
||||
BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunc = webClientHealthCheckFunction();
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunc) {
|
||||
@Override
|
||||
@@ -601,7 +574,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
Mockito.when(delegate.get()).thenReturn(Flux.just(Lists.list(serviceInstance1)));
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient)) {
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction()) {
|
||||
@Override
|
||||
protected Mono<Boolean> isAlive(ServiceInstance serviceInstance) {
|
||||
return Mono.just(true);
|
||||
@@ -633,7 +606,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
.doOnSubscribe(subscription -> subscribed.set(true)).doOnCancel(instancesCanceled::incrementAndGet));
|
||||
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient));
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction());
|
||||
|
||||
listSupplier.afterPropertiesSet();
|
||||
|
||||
@@ -656,7 +629,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
false);
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance),
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), healthCheckFunction(webClient));
|
||||
buildLoadBalancerClientFactory(SERVICE_ID, properties), webClientHealthCheckFunction());
|
||||
|
||||
boolean alive = listSupplier.isAlive(serviceInstance).block();
|
||||
|
||||
@@ -674,7 +647,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
port, false);
|
||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||
ServiceInstanceListSuppliers.from(serviceId, serviceInstance), loadBalancerClientFactory,
|
||||
healthCheckFunction(webClient));
|
||||
webClientHealthCheckFunction());
|
||||
|
||||
listSupplier.isAlive(serviceInstance).block();
|
||||
});
|
||||
@@ -682,6 +655,18 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
assertThat(exception).hasMessageContaining("Connection refused: /127.0.0.1:888");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> healthCheckFunctions() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
RestClient restClient = RestClient.create();
|
||||
return Stream.of(Arguments.of(healthCheckFunction(restTemplate)), Arguments.of(healthCheckFunction(restClient)),
|
||||
Arguments.of(webClientHealthCheckFunction()));
|
||||
}
|
||||
|
||||
private static BiFunction<ServiceInstance, String, Mono<Boolean>> webClientHealthCheckFunction() {
|
||||
WebClient webClient = WebClient.create();
|
||||
return healthCheckFunction(webClient);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2023 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.
|
||||
@@ -23,6 +23,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -61,4 +62,17 @@ final class ServiceInstanceListSuppliersTestUtils {
|
||||
});
|
||||
}
|
||||
|
||||
static BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunction(RestClient restClient) {
|
||||
return (serviceInstance, healthCheckPath) -> Mono.defer(() -> {
|
||||
URI uri = UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build().toUri();
|
||||
try {
|
||||
return Mono.just(
|
||||
HttpStatus.OK.equals(restClient.get().uri(uri).retrieve().toBodilessEntity().getStatusCode()));
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
return Mono.just(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user