Skip to content

Commit 4934ad8

Browse files
authored
fix(gax-grpc): add pick_first fallback to direct path service config (#4143)
The `Dependency Compatibility Test` CI workflow has been failing on the `InstantiatingGrpcChannelProviderTest` tests (e.g. `canUseDirectPath_happyPath`) with the following error during initialization: `java.lang.IllegalStateException: Default config is invalid: Status{code=UNKNOWN, description=None of [grpclb] specified by Service Config are available., cause=null}` **Root Cause & DNS Spam Issue:** As of `grpc-java` v1.77.0, the `grpc-grpclb` artifact is no longer implicitly included because the legacy `grpclb` load balancer plugin is deprecated (Tracked in #4012). However, `InstantiatingGrpcChannelProvider` still hardcoded `grpclb` as its primary DirectPath load balancing policy. This missing plugin crashes tests, but the backend Google `grpclb` lookaside servers were also officially turned down in July 2025. Because the library still explicitly requests `grpclb`, it causes gRPC to continuously spam DNS with `_grpclb._tcp.*` SRV queries trying to find those dead servers. This leads to ~22,000 NXDOMAIN DNS errors a day on user networks (Tracked in googleapis/java-pubsub#2404). **Fix:** This PR completely removes `grpclb` and replaces it with `pick_first` in `getDefaultDirectPathServiceConfig()`. We deliberately choose `pick_first` to preserve the original 2019 design intent (maintaining exactly one connection per pooled GAX channel to emulate CFE behavior) and to provide a safe, fail-open default. While Traffic Director relies on the `xds` API, configuring it as a default fallback would require complex bootstrap configurations and cause crashes for clients without that setup. `pick_first` stops the DNS spam entirely, ensures stability on modern gRPC versions, and resolves the test failures.
1 parent 48764e0 commit 4934ad8

File tree

2 files changed

+8
-17
lines changed

2 files changed

+8
-17
lines changed

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,7 @@ public ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> getChannelConfi
14341434
}
14351435

14361436
private static ImmutableMap<String, ?> getDefaultDirectPathServiceConfig() {
1437-
// When channel pooling is enabled, force the pick_first grpclb strategy.
1437+
// When channel pooling is enabled, force the pick_first strategy.
14381438
// This is necessary to avoid the multiplicative effect of creating channel pool with
14391439
// `poolSize` number of `ManagedChannel`s, each with a `subSetting` number of number of
14401440
// subchannels.
@@ -1443,13 +1443,8 @@ public ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> getChannelConfi
14431443
ImmutableMap<String, Object> pickFirstStrategy =
14441444
ImmutableMap.<String, Object>of("pick_first", ImmutableMap.of());
14451445

1446-
ImmutableMap<String, Object> childPolicy =
1447-
ImmutableMap.<String, Object>of("childPolicy", ImmutableList.of(pickFirstStrategy));
1448-
1449-
ImmutableMap<String, Object> grpcLbPolicy =
1450-
ImmutableMap.<String, Object>of("grpclb", childPolicy);
1451-
1452-
return ImmutableMap.<String, Object>of("loadBalancingConfig", ImmutableList.of(grpcLbPolicy));
1446+
return ImmutableMap.<String, Object>of(
1447+
"loadBalancingConfig", ImmutableList.of(pickFirstStrategy));
14531448
}
14541449

14551450
private static void validateEndpoint(String endpoint) {

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ void testToBuilder() {
235235
builder -> {
236236
throw new UnsupportedOperationException();
237237
};
238-
Map<String, ?> directPathServiceConfig = ImmutableMap.of("loadbalancingConfig", "grpclb");
238+
Map<String, ?> directPathServiceConfig = ImmutableMap.of("loadBalancingConfig", "pick_first");
239239
List<InstantiatingGrpcChannelProvider.HardBoundTokenTypes> hardBoundTokenTypes =
240240
new ArrayList<>();
241241
hardBoundTokenTypes.add(InstantiatingGrpcChannelProvider.HardBoundTokenTypes.ALTS);
@@ -549,11 +549,7 @@ void testWithDefaultDirectPathServiceConfig() {
549549
List<Map<String, ?>> lbConfigs = getAsObjectList(defaultServiceConfig, "loadBalancingConfig");
550550
assertThat(lbConfigs).hasSize(1);
551551
Map<String, ?> lbConfig = lbConfigs.get(0);
552-
Map<String, ?> grpclb = getAsObject(lbConfig, "grpclb");
553-
List<Map<String, ?>> childPolicies = getAsObjectList(grpclb, "childPolicy");
554-
assertThat(childPolicies).hasSize(1);
555-
Map<String, ?> childPolicy = childPolicies.get(0);
556-
assertThat(childPolicy.keySet()).containsExactly("pick_first");
552+
assertThat(lbConfig.keySet()).containsExactly("pick_first");
557553
}
558554

559555
@Nullable
@@ -599,10 +595,10 @@ void testWithCustomDirectPathServiceConfig() {
599595
ImmutableMap<String, Object> childPolicy =
600596
ImmutableMap.<String, Object>of(
601597
"childPolicy", ImmutableList.of(pickFirstStrategy), "foo", "bar");
602-
ImmutableMap<String, Object> grpcLbPolicy =
603-
ImmutableMap.<String, Object>of("grpclb", childPolicy);
598+
ImmutableMap<String, Object> customLbPolicy =
599+
ImmutableMap.<String, Object>of("my_custom_lb", childPolicy);
604600
Map<String, Object> passedServiceConfig = new HashMap<>();
605-
passedServiceConfig.put("loadBalancingConfig", ImmutableList.of(grpcLbPolicy));
601+
passedServiceConfig.put("loadBalancingConfig", ImmutableList.of(customLbPolicy));
606602

607603
InstantiatingGrpcChannelProvider provider =
608604
InstantiatingGrpcChannelProvider.newBuilder()

0 commit comments

Comments
 (0)