diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java index e4c5b1ea..bc6cd5da 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java @@ -100,6 +100,12 @@ public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalance return new EmptyResponse(); } + // Do not move position when there is only 1 instance, especially some suppliers + // have already filtered instances + if (instances.size() == 1) { + return new DefaultResponse(instances.get(0)); + } + // Ignore the sign bit, this allows pos to loop sequentially from 0 to // Integer.MAX_VALUE int pos = this.position.incrementAndGet() & Integer.MAX_VALUE; diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java index 574a33b1..50aa8e41 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java @@ -17,11 +17,13 @@ package org.springframework.cloud.loadbalancer.core; import java.util.ArrayList; +import java.util.Collections; import java.util.List; 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.loadbalancer.support.SimpleObjectProvider; @@ -52,6 +54,20 @@ class RoundRobinLoadBalancerTests { assertOrderEnforced(MAX_VALUE); } + @Test + void shouldNotMovePositionIfOnlyOneInstance() { + ServiceInstanceListSupplier supplier = mock(ServiceInstanceListSupplier.class); + when(supplier.get(any())).thenReturn(Flux.just(Collections.singletonList(new DefaultServiceInstance()))); + RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(supplier), + "shouldNotMovePositionIfOnlyOneInstance", 0); + + loadBalancer.choose().block(); + assertThat(loadBalancer.position).hasValue(0); + + loadBalancer.choose().block(); + assertThat(loadBalancer.position).hasValue(0); + } + @SuppressWarnings("all") void assertOrderEnforced(int seed) { List instances = new ArrayList<>();