From 4c707ecafaf2b76001f26c851c7d5c8b0ad05f6c Mon Sep 17 00:00:00 2001 From: Kannan J Date: Tue, 1 Oct 2024 11:21:08 +0530 Subject: [PATCH] Make address resolution error use the default service config (#11577) Fixes #11040. --- .../io/grpc/internal/ManagedChannelImpl.java | 10 +++- .../grpc/internal/ManagedChannelImplTest.java | 53 ++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index 07dcf9ee7bb..7e36086ac94 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -956,7 +956,15 @@ void updateConfigSelector(@Nullable InternalConfigSelector config) { // Must run in SynchronizationContext. void onConfigError() { if (configSelector.get() == INITIAL_PENDING_SELECTOR) { - updateConfigSelector(null); + // Apply Default Service Config if initial name resolution fails. + if (defaultServiceConfig != null) { + updateConfigSelector(defaultServiceConfig.getDefaultConfigSelector()); + lastServiceConfig = defaultServiceConfig; + channelLogger.log(ChannelLogLevel.ERROR, + "Initial Name Resolution error, using default service config"); + } else { + updateConfigSelector(null); + } } } diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index 4d42056b689..bea14bcef47 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -84,6 +84,7 @@ import io.grpc.InternalChannelz; import io.grpc.InternalChannelz.ChannelStats; import io.grpc.InternalChannelz.ChannelTrace; +import io.grpc.InternalChannelz.ChannelTrace.Event.Severity; import io.grpc.InternalConfigSelector; import io.grpc.InternalInstrumented; import io.grpc.LoadBalancer; @@ -123,6 +124,7 @@ import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider; import io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder; +import io.grpc.internal.ManagedChannelServiceConfig.MethodInfo; import io.grpc.internal.ServiceConfigUtil.PolicySelection; import io.grpc.internal.TestUtils.MockClientTransportInfo; import io.grpc.stub.ClientCalls; @@ -1127,6 +1129,55 @@ public void noMoreCallbackAfterLoadBalancerShutdown_configError() throws Interru verifyNoMoreInteractions(mockLoadBalancer); } + @Test + public void addressResolutionError_noPriorNameResolution_usesDefaultServiceConfig() + throws Exception { + Map rawServiceConfig = + parseConfig("{\"methodConfig\":[{" + + "\"name\":[{\"service\":\"service\"}]," + + "\"waitForReady\":true}]}"); + ManagedChannelServiceConfig managedChannelServiceConfig = + createManagedChannelServiceConfig(rawServiceConfig, null); + FakeNameResolverFactory nameResolverFactory = + new FakeNameResolverFactory.Builder(expectedUri) + .setServers(Collections.singletonList(new EquivalentAddressGroup(socketAddress))) + .setResolvedAtStart(false) + .build(); + nameResolverFactory.nextConfigOrError.set( + ConfigOrError.fromConfig(managedChannelServiceConfig)); + channelBuilder.nameResolverFactory(nameResolverFactory); + Map defaultServiceConfig = + parseConfig("{\"methodConfig\":[{" + + "\"name\":[{\"service\":\"service\"}]," + + "\"waitForReady\":true}]}"); + channelBuilder.defaultServiceConfig(defaultServiceConfig); + Status resolutionError = Status.UNAVAILABLE.withDescription("Resolution failed"); + channelBuilder.maxTraceEvents(10); + createChannel(); + FakeNameResolverFactory.FakeNameResolver resolver = nameResolverFactory.resolvers.get(0); + + resolver.listener.onError(resolutionError); + + InternalConfigSelector configSelector = channel.getConfigSelector(); + ManagedChannelServiceConfig config = + (ManagedChannelServiceConfig) configSelector.selectConfig(null).getConfig(); + MethodInfo methodConfig = config.getMethodConfig(method); + assertThat(methodConfig.waitForReady).isTrue(); + timer.forwardNanos(1234); + assertThat(getStats(channel).channelTrace.events).contains(new ChannelTrace.Event.Builder() + .setDescription("Initial Name Resolution error, using default service config") + .setSeverity(Severity.CT_ERROR) + .setTimestampNanos(0) + .build()); + + // Check that "lastServiceConfig" variable has been set above: a config resolution with the same + // config simply gets ignored and not gets reassigned. + resolver.resolved(); + timer.forwardNanos(1234); + assertThat(getStats(channel).channelTrace.events.stream().filter( + event -> event.description.equals("Service config changed")).count()).isEqualTo(0); + } + @Test public void interceptor() throws Exception { final AtomicLong atomic = new AtomicLong(); @@ -4595,7 +4646,7 @@ public void notUseDefaultImmediatelyIfEnableLookUp() throws Exception { int size = getStats(channel).channelTrace.events.size(); assertThat(getStats(channel).channelTrace.events.get(size - 1)) .isNotEqualTo(new ChannelTrace.Event.Builder() - .setDescription("Using default service config") + .setDescription("timer.forwardNanos(1234);") .setSeverity(ChannelTrace.Event.Severity.CT_INFO) .setTimestampNanos(timer.getTicker().read()) .build());