Skip to content

Commit cc0cb9b

Browse files
committed
fix(gax-grpc): resolve merge conflicts with feat/channelpool-resizing
2 parents 8992272 + defe1bb commit cc0cb9b

2 files changed

Lines changed: 22 additions & 103 deletions

File tree

sdk-platform-java/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/ChannelPoolSettings.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public abstract class ChannelPoolSettings {
6161
/** The maximum number of channels that can be added or removed at a time. */
6262
static final int DEFAULT_MAX_RESIZE_DELTA = 2;
6363

64+
// Arbitrary limit to prevent unbounded growth and protect server/client resources.
65+
// Capping at 25 ensures we don't scale too aggressively in a single cycle.
66+
private static final int MAX_ALLOWED_RESIZE_DELTA = 25;
67+
6468
/**
6569
* Threshold to start scaling down the channel pool.
6670
*
@@ -100,6 +104,11 @@ public abstract class ChannelPoolSettings {
100104
* the pool better handle sudden bursts or spikes in requests by allowing it to scale up faster.
101105
* Regardless of this setting, the number of channels will never exceed {@link
102106
* #getMaxChannelCount()}.
107+
*
108+
* <p><b>Note:</b> This value cannot exceed {@value #MAX_ALLOWED_RESIZE_DELTA}.
109+
*
110+
* <p><b>Warning:</b> Higher values for resize delta may still result in performance degradation
111+
* during spikes due to rapid scaling.
103112
*/
104113
public abstract int getMaxResizeDelta();
105114

@@ -208,6 +217,9 @@ public abstract static class Builder {
208217
* This acts as a rate limiter to prevent wild fluctuations. The pool resizes periodically
209218
* according to {@link #RESIZE_INTERVAL} (default 1 minute). During resizing, this value is
210219
* effectively capped by the bound configured via {@link #setMaxChannelCount}.
220+
*
221+
* <p><b>Warning:</b> Higher values for resize delta may still result in performance degradation
222+
* during spikes due to rapid scaling.
211223
*/
212224
public abstract Builder setMaxResizeDelta(int count);
213225

@@ -232,6 +244,12 @@ public ChannelPoolSettings build() {
232244
s.getInitialChannelCount() > 0, "Initial channel count must be greater than 0");
233245
Preconditions.checkState(
234246
s.getMaxResizeDelta() > 0, "Max resize delta must be greater than 0");
247+
Preconditions.checkState(
248+
s.getMaxResizeDelta() <= MAX_ALLOWED_RESIZE_DELTA,
249+
"Max resize delta cannot be greater than " + MAX_ALLOWED_RESIZE_DELTA);
250+
Preconditions.checkState(
251+
s.getMaxResizeDelta() <= s.getMaxChannelCount(),
252+
"Max resize delta cannot be greater than max channel count");
235253
return s;
236254
}
237255
}

sdk-platform-java/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/ChannelPoolTest.java

Lines changed: 4 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -851,109 +851,10 @@ void testDoubleRelease() throws Exception {
851851
}
852852

853853
@Test
854-
void settingsValidationFailsWhenMinChannelsExceedsMaxChannels() {
854+
void settingsValidationFailsWhenMaxResizeDeltaExceedsLimit() {
855855
ChannelPoolSettings.Builder builder =
856-
ChannelPoolSettings.builder().setMinChannelCount(2).setMaxChannelCount(1);
857-
Assertions.assertThrows(IllegalStateException.class, () -> builder.build());
858-
}
859-
860-
@Test
861-
void minChannelsClampedToMaxChannelCountUnderHighLoad() throws Exception {
862-
ScheduledExecutorService executor = Mockito.mock(ScheduledExecutorService.class);
863-
FixedExecutorProvider provider = FixedExecutorProvider.create(executor);
864-
865-
List<ManagedChannel> channels = new ArrayList<>();
866-
ChannelFactory channelFactory = createMockChannelFactory(channels, null);
867-
868-
pool =
869-
new ChannelPool(
870-
ChannelPoolSettings.builder()
871-
.setInitialChannelCount(1)
872-
.setMinRpcsPerChannel(1)
873-
.setMaxRpcsPerChannel(2)
874-
.setMaxResizeDelta(10) // Allow large growth
875-
.setMinChannelCount(1)
876-
.setMaxChannelCount(5)
877-
.build(),
878-
channelFactory,
879-
provider);
880-
assertThat(pool.entries.get()).hasSize(1);
881-
882-
// Add 20 RPCs, which would require 10 channels (20/2)
883-
// But max is 5
884-
for (int i = 0; i < 20; i++) {
885-
ClientCalls.futureUnaryCall(
886-
pool.newCall(METHOD_RECOGNIZE, CallOptions.DEFAULT), Color.getDefaultInstance());
887-
}
888-
889-
pool.resize();
890-
891-
// Should be clamped to maxChannelCount = 5
892-
assertThat(pool.entries.get()).hasSize(5);
893-
}
894-
895-
@Test
896-
void resizeDampenedByMaxResizeDelta() throws Exception {
897-
ScheduledExecutorService executor = Mockito.mock(ScheduledExecutorService.class);
898-
FixedExecutorProvider provider = FixedExecutorProvider.create(executor);
899-
900-
List<ManagedChannel> channels = new ArrayList<>();
901-
ChannelFactory channelFactory = createMockChannelFactory(channels, null);
902-
903-
pool =
904-
new ChannelPool(
905-
ChannelPoolSettings.builder()
906-
.setInitialChannelCount(1)
907-
.setMinRpcsPerChannel(1)
908-
.setMaxRpcsPerChannel(2)
909-
.setMaxResizeDelta(2) // Limit growth to 2 channels per cycle
910-
.setMinChannelCount(1)
911-
.setMaxChannelCount(10)
912-
.build(),
913-
channelFactory,
914-
provider);
915-
assertThat(pool.entries.get()).hasSize(1);
916-
917-
// Add 20 RPCs, which would require 10 channels (20/2)
918-
// Desired delta is +9 (10 - 1)
919-
// maxResizeDelta is 2, so it should be dampened to 2
920-
for (int i = 0; i < 20; i++) {
921-
ClientCalls.futureUnaryCall(
922-
pool.newCall(METHOD_RECOGNIZE, CallOptions.DEFAULT), Color.getDefaultInstance());
923-
}
924-
925-
pool.resize();
926-
927-
// Should be dampened to 1 + 2 = 3 channels
928-
assertThat(pool.entries.get()).hasSize(3);
929-
}
930-
931-
@Test
932-
void maxChannelsClampedToMinChannelCountUnderLowLoad() throws Exception {
933-
ScheduledExecutorService executor = Mockito.mock(ScheduledExecutorService.class);
934-
FixedExecutorProvider provider = FixedExecutorProvider.create(executor);
935-
936-
List<ManagedChannel> channels = new ArrayList<>();
937-
ChannelFactory channelFactory = createMockChannelFactory(channels, null);
938-
939-
pool =
940-
new ChannelPool(
941-
ChannelPoolSettings.builder()
942-
.setInitialChannelCount(5)
943-
.setMinRpcsPerChannel(1)
944-
.setMaxRpcsPerChannel(2)
945-
.setMinChannelCount(3)
946-
.setMaxChannelCount(10)
947-
.build(),
948-
channelFactory,
949-
provider);
950-
assertThat(pool.entries.get()).hasSize(5);
951-
952-
// With no outstanding RPCs, the pool should want to shrink to 0
953-
// But min is 3
954-
pool.resize();
955-
956-
// Should be clamped to minChannelCount = 3
957-
assertThat(pool.entries.get()).hasSize(3);
856+
ChannelPoolSettings.builder().setMaxResizeDelta(26).setMaxChannelCount(30);
857+
org.junit.jupiter.api.Assertions.assertThrows(
858+
IllegalStateException.class, () -> builder.build());
958859
}
959860
}

0 commit comments

Comments
 (0)