Compare commits

...

3 Commits

Author SHA1 Message Date
Olga MaciaszekSharma 6dc28f603b Add more docs. 1 year ago
Olga MaciaszekSharma d775fdcc60 Add more tests and docs. Remove deprecations. 1 year ago
Olga MaciaszekSharma 91313ff9b6 Call `get(Request request)` on delegates. 1 year ago
  1. 26
      docs/src/main/asciidoc/spring-cloud-commons.adoc
  2. 43
      spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java
  3. 22
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java
  4. 4
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java
  5. 19
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java
  6. 32
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java
  7. 21
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplier.java
  8. 8
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java
  9. 33
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java
  10. 6
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilderTests.java
  11. 33
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java

26
docs/src/main/asciidoc/spring-cloud-commons.adoc

@ -933,6 +933,11 @@ to `false`. @@ -933,6 +933,11 @@ to `false`.
WARNING: Although the basic, non-cached, implementation is useful for prototyping and testing, it's much less efficient than the cached versions, so we recommend always using the cached version in production. If the caching is already done by the `DiscoveryClient` implementation, for example `EurekaDiscoveryClient`, the load-balancer caching should be disabled to prevent double caching.
====
NOTE: When you create your own configuration, if you use `CachingServiceInstanceListSupplier` make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, `DiscoveryClientServiceInstanceListSupplier`, before any other filtering suppliers.
====
=== Zone-Based Load-Balancing
To enable zone-based load-balancing, we provide the `ZonePreferenceServiceInstanceListSupplier`.
@ -950,7 +955,7 @@ If the zone is `null` or there are no instances within the same zone, it returns @@ -950,7 +955,7 @@ If the zone is `null` or there are no instances within the same zone, it returns
In order to use the zone-based load-balancing approach, you will have to instantiate a `ZonePreferenceServiceInstanceListSupplier` bean in a <<custom-loadbalancer-configuration,custom configuration>>.
We use delegates to work with `ServiceInstanceListSupplier` beans.
We suggest passing a `DiscoveryClientServiceInstanceListSupplier` delegate in the constructor of `ZonePreferenceServiceInstanceListSupplier` and, in turn, wrapping the latter with a `CachingServiceInstanceListSupplier` to leverage <<loadbalancer-caching, LoadBalancer caching mechanism>>.
We suggest using a `DiscoveryClientServiceInstanceListSupplier` delegate, wrapping it with a `CachingServiceInstanceListSupplier` to leverage <<loadbalancer-caching, LoadBalancer caching mechanism>>, and then passing the resulting bean in the constructor of `ZonePreferenceServiceInstanceListSupplier`.
You can use this sample configuration to set it up:
@ -964,8 +969,8 @@ public class CustomLoadBalancerConfiguration { @@ -964,8 +969,8 @@ public class CustomLoadBalancerConfiguration {
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withZonePreference()
.withCaching()
.build(context);
}
}
@ -1026,6 +1031,12 @@ You can also pass your own `WebClient` or `RestTemplate` instance to be used for @@ -1026,6 +1031,12 @@ You can also pass your own `WebClient` or `RestTemplate` instance to be used for
WARNING: `HealthCheckServiceInstanceListSupplier` has its own caching mechanism based on Reactor Flux `replay()`. Therefore, if it's being used, you may want to skip wrapping that supplier with `CachingServiceInstanceListSupplier`.
====
NOTE: When you create your own configuration, `HealthCheckServiceInstanceListSupplier`, make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, `DiscoveryClientServiceInstanceListSupplier`, before any other filtering suppliers.
====
=== Same instance preference for LoadBalancer
You can set up the LoadBalancer in such a way that it prefers the instance that was previously selected, if that instance is available.
@ -1110,8 +1121,8 @@ public class CustomLoadBalancerConfiguration { @@ -1110,8 +1121,8 @@ public class CustomLoadBalancerConfiguration {
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withHints()
.withCaching()
.build(context);
}
}
@ -1221,11 +1232,18 @@ public class MyConfiguration { @@ -1221,11 +1232,18 @@ public class MyConfiguration {
}
}
----
====
NOTE: The classes you pass as `@LoadBalancerClient` or `@LoadBalancerClients` configuration arguments should either not be annotated with `@Configuration` or be outside component scan scope.
====
====
NOTE: When you create your own configuration, if you use `CachingServiceInstanceListSupplier` or `HealthCheckServiceInstanceListSupplier`, makes sure to use one of them, not both, and make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, `DiscoveryClientServiceInstanceListSupplier`, before any other filtering suppliers.
====
[[loadbalancer-lifecycle]]
=== Spring Cloud LoadBalancer Lifecycle
@ -1301,6 +1319,8 @@ The per-client configuration properties work for most of the properties, apart f @@ -1301,6 +1319,8 @@ The per-client configuration properties work for most of the properties, apart f
NOTE: For the properties where maps where already used, where you can specify a different value per-client without using the `clients` keyword (for example, `hints`, `health-check.path`), we have kept that behaviour in order to keep the library backwards compatible. It will be modified in the next major release.
NOTE: Starting with `3.1.7` in `2021.0.x` release train, `4.0.4` in `2022.0.x` release train and `4.1.0` in the `2023.0.x` release train, we have introduced the `callGetWithRequestOnDelegates` flag in `LoadBalancerProperties`. If this flag is set to `true`, `ServiceInstanceListSupplier#get(Request request)` method will be implemented to call `delegate.get(request)` in classes assignable from `DelegatingServiceInstanceListSupplier` that don't already implement that method, with the exclusion of `CachingServiceInstanceListSupplier` and `HealthCheckServiceInstanceListSupplier`, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. For `3.1.x` and `4.0.x` the flag is set to `false` by default, and since `4.1.0` it's going to be set to `true` by default.
== Spring Cloud Circuit Breaker
include::spring-cloud-circuitbreaker.adoc[leveloffset=+1]

43
spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java

@ -73,6 +73,19 @@ public class LoadBalancerProperties { @@ -73,6 +73,19 @@ public class LoadBalancerProperties {
*/
private boolean useRawStatusCodeInResponseData;
/**
* If this flag is set to {@code true},
* {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented
* to call {@code delegate.get(request)} in classes assignable from
* {@code DelegatingServiceInstanceListSupplier} that don't already implement that
* method, with the exclusion of {@code CachingServiceInstanceListSupplier} and
* {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the
* instance supplier hierarchy directly after the supplier performing instance
* retrieval over the network, before any request-based filtering is done. Note: in
* 4.1, this behaviour will become the default
*/
private boolean callGetWithRequestOnDelegates;
public HealthCheck getHealthCheck() {
return healthCheck;
}
@ -134,6 +147,36 @@ public class LoadBalancerProperties { @@ -134,6 +147,36 @@ public class LoadBalancerProperties {
this.useRawStatusCodeInResponseData = useRawStatusCodeInResponseData;
}
/**
* If this flag is set to {@code true},
* {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented
* to call {@code delegate.get(request)} in classes assignable from
* {@code DelegatingServiceInstanceListSupplier} that don't already implement that
* method, with the exclusion of {@code CachingServiceInstanceListSupplier} and
* {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the
* instance supplier hierarchy directly after the supplier performing instance
* retrieval over the network, before any request-based filtering is done. Note: in
* 4.1, this behaviour will become the default
*/
public boolean isCallGetWithRequestOnDelegates() {
return callGetWithRequestOnDelegates;
}
/**
* If this flag is set to {@code true},
* {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented
* to call {@code delegate.get(request)} in classes assignable from
* {@code DelegatingServiceInstanceListSupplier} that don't already implement that
* method, with the exclusion of {@code CachingServiceInstanceListSupplier} and
* {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the
* instance supplier hierarchy directly after the supplier performing instance
* retrieval over the network, before any request-based filtering is done. Note: in
* 4.1, this behaviour will become the default
*/
public void setCallGetWithRequestOnDelegates(boolean callGetWithRequestOnDelegates) {
this.callGetWithRequestOnDelegates = callGetWithRequestOnDelegates;
}
public static class StickySession {
/**

22
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java

@ -93,7 +93,7 @@ public class LoadBalancerClientConfiguration { @@ -93,7 +93,7 @@ public class LoadBalancerClientConfiguration {
@Conditional(ZonePreferenceConfigurationCondition.class)
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withZonePreference().withCaching()
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().withZonePreference()
.build(context);
}
@ -119,8 +119,8 @@ public class LoadBalancerClientConfiguration { @@ -119,8 +119,8 @@ public class LoadBalancerClientConfiguration {
@Conditional(RequestBasedStickySessionConfigurationCondition.class)
public ServiceInstanceListSupplier requestBasedStickySessionDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withRequestBasedStickySession()
.withCaching().build(context);
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching()
.withRequestBasedStickySession().build(context);
}
@Bean
@ -129,8 +129,8 @@ public class LoadBalancerClientConfiguration { @@ -129,8 +129,8 @@ public class LoadBalancerClientConfiguration {
@Conditional(SameInstancePreferenceConfigurationCondition.class)
public ServiceInstanceListSupplier sameInstancePreferenceServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withSameInstancePreference()
.withCaching().build(context);
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching()
.withSameInstancePreference().build(context);
}
}
@ -155,8 +155,8 @@ public class LoadBalancerClientConfiguration { @@ -155,8 +155,8 @@ public class LoadBalancerClientConfiguration {
@Conditional(ZonePreferenceConfigurationCondition.class)
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withZonePreference()
.withCaching().build(context);
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching()
.withZonePreference().build(context);
}
@Bean
@ -175,8 +175,8 @@ public class LoadBalancerClientConfiguration { @@ -175,8 +175,8 @@ public class LoadBalancerClientConfiguration {
@Conditional(RequestBasedStickySessionConfigurationCondition.class)
public ServiceInstanceListSupplier requestBasedStickySessionDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withRequestBasedStickySession()
.withCaching().build(context);
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching()
.withRequestBasedStickySession().build(context);
}
@Bean
@ -185,8 +185,8 @@ public class LoadBalancerClientConfiguration { @@ -185,8 +185,8 @@ public class LoadBalancerClientConfiguration {
@Conditional(SameInstancePreferenceConfigurationCondition.class)
public ServiceInstanceListSupplier sameInstancePreferenceServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withSameInstancePreference()
.withCaching().build(context);
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching()
.withSameInstancePreference().build(context);
}
}

4
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java

@ -38,12 +38,12 @@ public abstract class DelegatingServiceInstanceListSupplier @@ -38,12 +38,12 @@ public abstract class DelegatingServiceInstanceListSupplier
}
public ServiceInstanceListSupplier getDelegate() {
return this.delegate;
return delegate;
}
@Override
public String getServiceId() {
return this.delegate.getServiceId();
return delegate.getServiceId();
}
@Override

19
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java

@ -24,6 +24,8 @@ import org.apache.commons.logging.LogFactory; @@ -24,6 +24,8 @@ import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
/**
* An implementation of {@link ServiceInstanceListSupplier} that selects the previously
@ -39,10 +41,19 @@ public class SameInstancePreferenceServiceInstanceListSupplier extends Delegatin @@ -39,10 +41,19 @@ public class SameInstancePreferenceServiceInstanceListSupplier extends Delegatin
private ServiceInstance previouslyReturnedInstance;
private boolean callGetWithRequestOnDelegates;
public SameInstancePreferenceServiceInstanceListSupplier(ServiceInstanceListSupplier delegate) {
super(delegate);
}
public SameInstancePreferenceServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerClientFactory) {
super(delegate);
callGetWithRequestOnDelegates = loadBalancerClientFactory.getProperties(getServiceId())
.isCallGetWithRequestOnDelegates();
}
@Override
public String getServiceId() {
return delegate.getServiceId();
@ -53,6 +64,14 @@ public class SameInstancePreferenceServiceInstanceListSupplier extends Delegatin @@ -53,6 +64,14 @@ public class SameInstancePreferenceServiceInstanceListSupplier extends Delegatin
return delegate.get().map(this::filteredBySameInstancePreference);
}
@Override
public Flux<List<ServiceInstance>> get(Request request) {
if (callGetWithRequestOnDelegates) {
return delegate.get(request).map(this::filteredBySameInstancePreference);
}
return get();
}
private List<ServiceInstance> filteredBySameInstancePreference(List<ServiceInstance> serviceInstances) {
if (previouslyReturnedInstance != null && serviceInstances.contains(previouslyReturnedInstance)) {
if (LOG.isDebugEnabled()) {

32
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java

@ -57,8 +57,6 @@ public final class ServiceInstanceListSupplierBuilder { @@ -57,8 +57,6 @@ public final class ServiceInstanceListSupplierBuilder {
private Creator baseCreator;
private DelegateCreator cachingCreator;
private final List<DelegateCreator> creators = new ArrayList<>();
ServiceInstanceListSupplierBuilder() {
@ -148,8 +146,10 @@ public final class ServiceInstanceListSupplierBuilder { @@ -148,8 +146,10 @@ public final class ServiceInstanceListSupplierBuilder {
* @return the {@link ServiceInstanceListSupplierBuilder} object
*/
public ServiceInstanceListSupplierBuilder withSameInstancePreference() {
DelegateCreator creator = (context,
delegate) -> new SameInstancePreferenceServiceInstanceListSupplier(delegate);
DelegateCreator creator = (context, delegate) -> {
LoadBalancerClientFactory loadBalancerClientFactory = context.getBean(LoadBalancerClientFactory.class);
return new SameInstancePreferenceServiceInstanceListSupplier(delegate, loadBalancerClientFactory);
};
this.creators.add(creator);
return this;
}
@ -191,8 +191,9 @@ public final class ServiceInstanceListSupplierBuilder { @@ -191,8 +191,9 @@ public final class ServiceInstanceListSupplierBuilder {
*/
public ServiceInstanceListSupplierBuilder withZonePreference() {
DelegateCreator creator = (context, delegate) -> {
LoadBalancerClientFactory loadBalancerClientFactory = context.getBean(LoadBalancerClientFactory.class);
LoadBalancerZoneConfig zoneConfig = context.getBean(LoadBalancerZoneConfig.class);
return new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig);
return new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig, loadBalancerClientFactory);
};
this.creators.add(creator);
return this;
@ -206,8 +207,9 @@ public final class ServiceInstanceListSupplierBuilder { @@ -206,8 +207,9 @@ public final class ServiceInstanceListSupplierBuilder {
*/
public ServiceInstanceListSupplierBuilder withZonePreference(String zoneName) {
DelegateCreator creator = (context, delegate) -> {
LoadBalancerClientFactory loadBalancerClientFactory = context.getBean(LoadBalancerClientFactory.class);
LoadBalancerZoneConfig zoneConfig = new LoadBalancerZoneConfig(zoneName);
return new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig);
return new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig, loadBalancerClientFactory);
};
this.creators.add(creator);
return this;
@ -228,19 +230,15 @@ public final class ServiceInstanceListSupplierBuilder { @@ -228,19 +230,15 @@ public final class ServiceInstanceListSupplierBuilder {
}
/**
* If {@link LoadBalancerCacheManager} is available in the context, wraps created
* {@link ServiceInstanceListSupplier} hierarchy with a
* {@link CachingServiceInstanceListSupplier} instance to provide a caching mechanism
* for service instances. Uses {@link ObjectProvider} to lazily resolve
* If {@link LoadBalancerCacheManager} is available in the context, adds a
* {@link CachingServiceInstanceListSupplier} instance to the
* {@link ServiceInstanceListSupplier} hierarchy to provide a caching mechanism for
* service instances. Uses {@link ObjectProvider} to lazily resolve
* {@link LoadBalancerCacheManager}.
* @return the {@link ServiceInstanceListSupplierBuilder} object
*/
public ServiceInstanceListSupplierBuilder withCaching() {
if (cachingCreator != null && LOG.isWarnEnabled()) {
LOG.warn(
"Overriding a previously set cachingCreator with a CachingServiceInstanceListSupplier-based cachingCreator.");
}
this.cachingCreator = (context, delegate) -> {
DelegateCreator creator = (context, delegate) -> {
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
.getBeanProvider(LoadBalancerCacheManager.class);
if (cacheManagerProvider.getIfAvailable() != null) {
@ -251,6 +249,7 @@ public final class ServiceInstanceListSupplierBuilder { @@ -251,6 +249,7 @@ public final class ServiceInstanceListSupplierBuilder {
}
return delegate;
};
creators.add(creator);
return this;
}
@ -297,9 +296,6 @@ public final class ServiceInstanceListSupplierBuilder { @@ -297,9 +296,6 @@ public final class ServiceInstanceListSupplierBuilder {
supplier = creator.apply(context, supplier);
}
if (this.cachingCreator != null) {
supplier = this.cachingCreator.apply(context, supplier);
}
return supplier;
}

21
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplier.java

@ -23,6 +23,8 @@ import java.util.Map; @@ -23,6 +23,8 @@ import java.util.Map;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.loadbalancer.config.LoadBalancerZoneConfig;
/**
@ -43,17 +45,36 @@ public class ZonePreferenceServiceInstanceListSupplier extends DelegatingService @@ -43,17 +45,36 @@ public class ZonePreferenceServiceInstanceListSupplier extends DelegatingService
private String zone;
private boolean callGetWithRequestOnDelegates;
public ZonePreferenceServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
LoadBalancerZoneConfig zoneConfig) {
super(delegate);
this.zoneConfig = zoneConfig;
}
public ZonePreferenceServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
LoadBalancerZoneConfig zoneConfig,
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerClientFactory) {
super(delegate);
this.zoneConfig = zoneConfig;
callGetWithRequestOnDelegates = loadBalancerClientFactory.getProperties(getServiceId())
.isCallGetWithRequestOnDelegates();
}
@Override
public Flux<List<ServiceInstance>> get() {
return getDelegate().get().map(this::filteredByZone);
}
@Override
public Flux<List<ServiceInstance>> get(Request request) {
if (callGetWithRequestOnDelegates) {
return getDelegate().get(request).map(this::filteredByZone);
}
return get();
}
private List<ServiceInstance> filteredByZone(List<ServiceInstance> serviceInstances) {
if (zone == null) {
zone = zoneConfig.getZone();

8
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java

@ -91,10 +91,10 @@ class LoadBalancerClientConfigurationTests { @@ -91,10 +91,10 @@ class LoadBalancerClientConfigurationTests {
reactiveDiscoveryClientRunner.withPropertyValues("spring.cloud.loadbalancer.configurations=zone-preference")
.run(context -> {
ServiceInstanceListSupplier supplier = context.getBean(ServiceInstanceListSupplier.class);
then(supplier).isInstanceOf(CachingServiceInstanceListSupplier.class);
then(supplier).isInstanceOf(ZonePreferenceServiceInstanceListSupplier.class);
ServiceInstanceListSupplier delegate = ((DelegatingServiceInstanceListSupplier) supplier)
.getDelegate();
then(delegate).isInstanceOf(ZonePreferenceServiceInstanceListSupplier.class);
then(delegate).isInstanceOf(CachingServiceInstanceListSupplier.class);
ServiceInstanceListSupplier secondDelegate = ((DelegatingServiceInstanceListSupplier) delegate)
.getDelegate();
then(secondDelegate).isInstanceOf(DiscoveryClientServiceInstanceListSupplier.class);
@ -119,10 +119,10 @@ class LoadBalancerClientConfigurationTests { @@ -119,10 +119,10 @@ class LoadBalancerClientConfigurationTests {
.withPropertyValues("spring.cloud.loadbalancer.configurations=request-based-sticky-session")
.run(context -> {
ServiceInstanceListSupplier supplier = context.getBean(ServiceInstanceListSupplier.class);
then(supplier).isInstanceOf(CachingServiceInstanceListSupplier.class);
then(supplier).isInstanceOf(RequestBasedStickySessionServiceInstanceListSupplier.class);
ServiceInstanceListSupplier delegate = ((DelegatingServiceInstanceListSupplier) supplier)
.getDelegate();
then(delegate).isInstanceOf(RequestBasedStickySessionServiceInstanceListSupplier.class);
then(delegate).isInstanceOf(CachingServiceInstanceListSupplier.class);
ServiceInstanceListSupplier secondDelegate = ((DelegatingServiceInstanceListSupplier) delegate)
.getDelegate();
then(secondDelegate).isInstanceOf(DiscoveryClientServiceInstanceListSupplier.class);

33
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java

@ -19,13 +19,20 @@ package org.springframework.cloud.loadbalancer.core; @@ -19,13 +19,20 @@ package org.springframework.cloud.loadbalancer.core;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -39,8 +46,9 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { @@ -39,8 +46,9 @@ class SameInstancePreferenceServiceInstanceListSupplierTests {
private final DiscoveryClientServiceInstanceListSupplier delegate = mock(
DiscoveryClientServiceInstanceListSupplier.class);
private final SameInstancePreferenceServiceInstanceListSupplier supplier = new SameInstancePreferenceServiceInstanceListSupplier(
delegate);
private final LoadBalancerClientFactory loadBalancerClientFactory = mock(LoadBalancerClientFactory.class);
private SameInstancePreferenceServiceInstanceListSupplier supplier;
private final ServiceInstance first = serviceInstance("test-1");
@ -48,6 +56,14 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { @@ -48,6 +56,14 @@ class SameInstancePreferenceServiceInstanceListSupplierTests {
private final ServiceInstance third = serviceInstance("test-3");
@BeforeEach
void setUp() {
LoadBalancerProperties properties = new LoadBalancerProperties();
properties.setCallGetWithRequestOnDelegates(true);
when(loadBalancerClientFactory.getProperties(any())).thenReturn(properties);
supplier = new SameInstancePreferenceServiceInstanceListSupplier(delegate, loadBalancerClientFactory);
}
@Test
void shouldReturnPreviouslySelectedInstanceIfAvailable() {
when(delegate.get()).thenReturn(Flux.just(Arrays.asList(first, second, third)));
@ -69,7 +85,7 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { @@ -69,7 +85,7 @@ class SameInstancePreferenceServiceInstanceListSupplierTests {
}
@Test
void shouldReturnAllInstancesFromDelegateIfPreviouslySelectedInstanceIfAvailable() {
void shouldReturnAllInstancesFromDelegateIfPreviouslySelectedInstanceIsNotAvailable() {
when(delegate.get()).thenReturn(Flux.just(Arrays.asList(second, third)));
supplier.selectedServiceInstance(first);
@ -78,6 +94,17 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { @@ -78,6 +94,17 @@ class SameInstancePreferenceServiceInstanceListSupplierTests {
assertThat(instances).hasSize(2);
}
@Test
void shouldCallGetRequestOnDelegate() {
Request<DefaultRequestContext> request = new DefaultRequest<>(new DefaultRequestContext());
when(delegate.get()).thenReturn(Flux.just(Arrays.asList(first, second, third)));
when(delegate.get(request)).thenReturn(Flux.just(Arrays.asList(first, second)));
List<ServiceInstance> instances = supplier.get(request).blockFirst();
assertThat(instances).hasSize(2);
}
private DefaultServiceInstance serviceInstance(String instanceId) {
return new DefaultServiceInstance(instanceId, "test", "http://test.test", 9080, false);
}

6
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilderTests.java

@ -37,11 +37,9 @@ public class ServiceInstanceListSupplierBuilderTests { @@ -37,11 +37,9 @@ public class ServiceInstanceListSupplierBuilderTests {
public void testBuilder() {
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class).run(context -> {
ServiceInstanceListSupplier supplier = ServiceInstanceListSupplier.builder().withDiscoveryClient()
.withHealthChecks().withCaching().build(context);
assertThat(supplier).isInstanceOf(CachingServiceInstanceListSupplier.class);
.withHealthChecks().build(context);
assertThat(supplier).isInstanceOf(HealthCheckServiceInstanceListSupplier.class);
DelegatingServiceInstanceListSupplier delegating = (DelegatingServiceInstanceListSupplier) supplier;
assertThat(delegating.getDelegate()).isInstanceOf(HealthCheckServiceInstanceListSupplier.class);
delegating = (DelegatingServiceInstanceListSupplier) delegating.getDelegate();
assertThat(delegating.getDelegate()).isInstanceOf(DiscoveryClientServiceInstanceListSupplier.class);
});
}

33
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java

@ -22,15 +22,22 @@ import java.util.HashMap; @@ -22,15 +22,22 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.loadbalancer.config.LoadBalancerZoneConfig;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -46,8 +53,9 @@ class ZonePreferenceServiceInstanceListSupplierTests { @@ -46,8 +53,9 @@ class ZonePreferenceServiceInstanceListSupplierTests {
private final LoadBalancerZoneConfig zoneConfig = new LoadBalancerZoneConfig(null);
private final ZonePreferenceServiceInstanceListSupplier supplier = new ZonePreferenceServiceInstanceListSupplier(
delegate, zoneConfig);
private ZonePreferenceServiceInstanceListSupplier supplier;
private final LoadBalancerClientFactory loadBalancerClientFactory = mock(LoadBalancerClientFactory.class);
private final ServiceInstance first = serviceInstance("test-1", buildZoneMetadata("zone1"));
@ -59,6 +67,14 @@ class ZonePreferenceServiceInstanceListSupplierTests { @@ -59,6 +67,14 @@ class ZonePreferenceServiceInstanceListSupplierTests {
private final ServiceInstance fifth = serviceInstance("test-5", buildZoneMetadata(null));
@BeforeEach
void setUp() {
LoadBalancerProperties properties = new LoadBalancerProperties();
properties.setCallGetWithRequestOnDelegates(true);
when(loadBalancerClientFactory.getProperties(any())).thenReturn(properties);
supplier = new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig, loadBalancerClientFactory);
}
@Test
void shouldFilterInstancesByZone() {
zoneConfig.setZone("zone1");
@ -73,6 +89,19 @@ class ZonePreferenceServiceInstanceListSupplierTests { @@ -73,6 +89,19 @@ class ZonePreferenceServiceInstanceListSupplierTests {
assertThat(filtered).doesNotContain(fifth);
}
@Test
void shouldCallGetRequestOnDelegate() {
zoneConfig.setZone("zone1");
Request<DefaultRequestContext> request = new DefaultRequest<>(new DefaultRequestContext());
when(delegate.get()).thenReturn(Flux.just(Arrays.asList(first, second, third, fourth, fifth)));
when(delegate.get(request)).thenReturn(Flux.just(Arrays.asList(first, third, fourth, fifth)));
List<ServiceInstance> filtered = supplier.get(request).blockFirst();
assertThat(filtered).hasSize(1);
assertThat(filtered).containsOnly(first);
}
@Test
void shouldReturnAllInstancesIfNoZoneInstances() {
zoneConfig.setZone("zone1");

Loading…
Cancel
Save