Skip to content

Commit 441c2bc

Browse files
loadbalancer: remove RoundRobinLoadBalancerBuilderProvider (#3137)
Motivation: Now that DefaultLoadBalancer is in the main loadbalancer package we can avoid using a provider to facilitate the migration. Modifications: Remove the migration provider and instead use the types directly.
1 parent e4d4418 commit 441c2bc

6 files changed

+133
-230
lines changed

servicetalk-loadbalancer/src/main/java/io/servicetalk/loadbalancer/RoundRobinLoadBalancerFactory.java

+70-4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
public final class RoundRobinLoadBalancerFactory<ResolvedAddress, C extends LoadBalancedConnection>
5656
implements LoadBalancerFactory<ResolvedAddress, C> {
5757

58+
static final String ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER =
59+
"io.servicetalk.loadbalancer.roundRobinUsesDefaultLoadBalancer";
60+
5861
private final String id;
5962
private final int linearSearchSpace;
6063
@Nullable
@@ -74,17 +77,21 @@ public <T extends C> LoadBalancer<T> newLoadBalancer(
7477
final String targetResource,
7578
final Publisher<? extends Collection<? extends ServiceDiscovererEvent<ResolvedAddress>>> eventPublisher,
7679
final ConnectionFactory<ResolvedAddress, T> connectionFactory) {
77-
return new RoundRobinLoadBalancer<>(id, targetResource, eventPublisher, connectionFactory,
78-
linearSearchSpace, healthCheckConfig);
80+
// We have to indirect here instead of at the `Builder.build()` call because as it turns out
81+
// `Builder.build()` has a return type of RoundRobinLoadBalancerFactory and is public API.
82+
return useDefaultLoadBalancer() ?
83+
buildDefaultLoadBalancerFactory(targetResource, eventPublisher, connectionFactory) :
84+
new RoundRobinLoadBalancer<>(
85+
id, targetResource, eventPublisher, connectionFactory, linearSearchSpace, healthCheckConfig);
7986
}
8087

8188
@Override
8289
public LoadBalancer<C> newLoadBalancer(
8390
final Publisher<? extends Collection<? extends ServiceDiscovererEvent<ResolvedAddress>>> eventPublisher,
8491
final ConnectionFactory<ResolvedAddress, C> connectionFactory,
8592
final String targetResource) {
86-
return new RoundRobinLoadBalancer<>(id, targetResource, eventPublisher, connectionFactory,
87-
linearSearchSpace, healthCheckConfig);
93+
// For now, we forward to the deprecated method since it is more generic.
94+
return newLoadBalancer(targetResource, eventPublisher, connectionFactory);
8895
}
8996

9097
@Override
@@ -102,6 +109,59 @@ public String toString() {
102109
'}';
103110
}
104111

112+
private <T extends C> LoadBalancer<T> buildDefaultLoadBalancerFactory(
113+
final String targetResource,
114+
final Publisher<? extends Collection<? extends ServiceDiscovererEvent<ResolvedAddress>>> eventPublisher,
115+
final ConnectionFactory<ResolvedAddress, T> connectionFactory) {
116+
final int healthCheckFailedConnectionsThreshold;
117+
final Duration healthCheckInterval;
118+
final Duration healthCheckJitter;
119+
final Duration healthCheckResubscribeInterval;
120+
final Duration healthCheckResubscribeJitter;
121+
final Executor backgroundExecutor;
122+
if (healthCheckConfig == null) {
123+
healthCheckFailedConnectionsThreshold = -1; // disabled, the rest are fillers.
124+
healthCheckInterval = DEFAULT_HEALTH_CHECK_INTERVAL;
125+
healthCheckJitter = DEFAULT_HEALTH_CHECK_JITTER;
126+
healthCheckResubscribeInterval = DEFAULT_HEALTH_CHECK_RESUBSCRIBE_INTERVAL;
127+
healthCheckResubscribeJitter = DEFAULT_HEALTH_CHECK_JITTER;
128+
backgroundExecutor = null;
129+
} else {
130+
healthCheckFailedConnectionsThreshold = healthCheckConfig.failedThreshold;
131+
healthCheckInterval = healthCheckConfig.healthCheckInterval;
132+
healthCheckJitter = healthCheckConfig.jitter;
133+
healthCheckResubscribeInterval = healthCheckConfig.resubscribeInterval;
134+
healthCheckResubscribeJitter = healthCheckConfig.healthCheckResubscribeJitter;
135+
backgroundExecutor = healthCheckConfig.executor;
136+
}
137+
138+
OutlierDetectorConfig outlierDetectorConfig = new OutlierDetectorConfig.Builder()
139+
.ewmaHalfLife(Duration.ZERO)
140+
// disable the xDS outlier detectors
141+
.enforcingFailurePercentage(0)
142+
.enforcingSuccessRate(0)
143+
.enforcingConsecutive5xx(0)
144+
// set the ServiceTalk L4 connection outlier detector settings
145+
.failedConnectionsThreshold(healthCheckFailedConnectionsThreshold)
146+
.failureDetectorInterval(healthCheckInterval, healthCheckJitter)
147+
.serviceDiscoveryResubscribeInterval(healthCheckResubscribeInterval, healthCheckResubscribeJitter)
148+
.build();
149+
LoadBalancingPolicy<ResolvedAddress, T> loadBalancingPolicy =
150+
LoadBalancingPolicies.roundRobin()
151+
.failOpen(false)
152+
.ignoreWeights(true)
153+
.build();
154+
LoadBalancerBuilder<ResolvedAddress, T> builder = LoadBalancers.builder(id);
155+
if (backgroundExecutor != null) {
156+
builder = builder.backgroundExecutor(backgroundExecutor);
157+
}
158+
return builder.outlierDetectorConfig(outlierDetectorConfig)
159+
.loadBalancingPolicy(loadBalancingPolicy)
160+
.connectionSelectorPolicy(ConnectionSelectorPolicies.linearSearch(linearSearchSpace))
161+
.build()
162+
.newLoadBalancer(eventPublisher, connectionFactory, targetResource);
163+
}
164+
105165
/**
106166
* Builder for {@link RoundRobinLoadBalancerFactory}.
107167
*
@@ -227,4 +287,10 @@ static Executor getInstance() {
227287
return INSTANCE;
228288
}
229289
}
290+
291+
private static boolean useDefaultLoadBalancer() {
292+
// Enabled by default.
293+
String propValue = System.getProperty(ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER);
294+
return propValue == null || Boolean.parseBoolean(propValue);
295+
}
230296
}

servicetalk-loadbalancer/src/main/java/io/servicetalk/loadbalancer/RoundRobinToDefaultLBMigrationProvider.java

-149
This file was deleted.

servicetalk-loadbalancer/src/main/resources/META-INF/services/io.servicetalk.loadbalancer.RoundRobinLoadBalancerBuilderProvider

-1
This file was deleted.

servicetalk-loadbalancer/src/test/java/io/servicetalk/loadbalancer/RoundRobinLoadBalancerBuilderProviderTest.java

-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.concurrent.atomic.AtomicInteger;
2727
import java.util.concurrent.atomic.AtomicReference;
2828

29-
import static io.servicetalk.loadbalancer.RoundRobinToDefaultLBMigrationProvider.PROPERTY_NAME;
3029
import static org.hamcrest.MatcherAssert.assertThat;
3130
import static org.hamcrest.Matchers.is;
3231

@@ -35,13 +34,11 @@ class RoundRobinLoadBalancerBuilderProviderTest {
3534
@BeforeEach
3635
void reset() {
3736
TestRoundRobinLoadBalancerBuilderProvider.reset();
38-
System.setProperty(PROPERTY_NAME, Boolean.FALSE.toString());
3937
}
4038

4139
@AfterEach
4240
void deactivate() {
4341
TestRoundRobinLoadBalancerBuilderProvider.activated.set(false);
44-
System.setProperty(PROPERTY_NAME, Boolean.TRUE.toString());
4542
}
4643

4744
@Test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright © 2024 Apple Inc. and the ServiceTalk project authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.servicetalk.loadbalancer;
17+
18+
import io.servicetalk.client.api.ConnectionFactory;
19+
import io.servicetalk.client.api.LoadBalancer;
20+
import io.servicetalk.concurrent.api.Publisher;
21+
import io.servicetalk.concurrent.api.Single;
22+
23+
import org.junit.jupiter.api.AfterEach;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.parallel.Execution;
26+
import org.junit.jupiter.api.parallel.ExecutionMode;
27+
28+
import static io.servicetalk.loadbalancer.RoundRobinLoadBalancerFactory.ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER;
29+
import static org.hamcrest.MatcherAssert.assertThat;
30+
import static org.hamcrest.Matchers.instanceOf;
31+
32+
@Execution(ExecutionMode.SAME_THREAD)
33+
final class RoundRobinLoadBalancerFactoryTest {
34+
35+
@AfterEach
36+
void cleanup() {
37+
System.clearProperty(ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER);
38+
}
39+
40+
@Test
41+
void generateDefaultLoadBalancerIfEnabled() {
42+
System.setProperty(ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER, "true");
43+
assertThat(getLoadBalancer(), instanceOf(DefaultLoadBalancer.class));
44+
}
45+
46+
@Test
47+
void doesNotGenerateDefaultLoadBalancerIfDisabled() {
48+
System.setProperty(ROUND_ROBIN_USER_DEFAULT_LOAD_BALANCER, "false");
49+
assertThat(getLoadBalancer(), instanceOf(RoundRobinLoadBalancer.class));
50+
}
51+
52+
@Test
53+
void defaultResultIsDefaultLoadBalancer() {
54+
assertThat(getLoadBalancer(), instanceOf(DefaultLoadBalancer.class));
55+
}
56+
57+
static LoadBalancer<TestLoadBalancedConnection> getLoadBalancer() {
58+
ConnectionFactory<String, TestLoadBalancedConnection> connectionFactory =
59+
new TestConnectionFactory(ignored -> Single.never());
60+
return RoundRobinLoadBalancers.<String, TestLoadBalancedConnection>builder("balancer").build()
61+
.newLoadBalancer(Publisher.never(), connectionFactory, "targetResource");
62+
}
63+
}

0 commit comments

Comments
 (0)