From c3277441f8792c523e396cf43425d4a963f09398 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 13 Jun 2022 13:55:46 -0700 Subject: [PATCH] core: Clear ConfigSelector in panic mode If the failure is before the NameResolver has returned the first time, RPCs would be queued waiting for service config. We don't want to use the ConfigSelector, as we are trying to circumvent the NameResolver and LoadBalancer. Fixes #9257 --- .../io/grpc/internal/ManagedChannelImpl.java | 4 +++ .../grpc/internal/ManagedChannelImplTest.java | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index b0d07efe254..bbd45cf34ca 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -887,6 +887,7 @@ public String toString() { } updateSubchannelPicker(new PanicSubchannelPicker()); + realChannel.updateConfigSelector(null); channelLogger.log(ChannelLogLevel.ERROR, "PANIC! Entering TRANSIENT_FAILURE"); channelStateManager.gotoState(TRANSIENT_FAILURE); } @@ -1755,6 +1756,9 @@ final class NamesResolved implements Runnable { @SuppressWarnings("ReferenceEquality") @Override public void run() { + if (ManagedChannelImpl.this.nameResolver != resolver) { + return; + } List servers = resolutionResult.getAddresses(); channelLogger.log( diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index f47954e2215..3f3951a4524 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -2799,6 +2799,40 @@ public void run() { panicExpected = true; } + @Test + public void panic_atStart() { + final RuntimeException panicReason = new RuntimeException("Simulated NR exception"); + final NameResolver failingResolver = new NameResolver() { + @Override public String getServiceAuthority() { + return "fake-authority"; + } + + @Override public void start(Listener2 listener) { + throw panicReason; + } + + @Override public void shutdown() {} + }; + channelBuilder.nameResolverFactory(new NameResolver.Factory() { + @Override public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) { + return failingResolver; + } + + @Override public String getDefaultScheme() { + return "fakescheme"; + } + }); + createChannel(); + + // RPCs fail immediately + ClientCall call = + channel.newCall(method, CallOptions.DEFAULT.withoutWaitForReady()); + call.start(mockCallListener, new Metadata()); + executor.runDueTasks(); + verifyCallListenerClosed(mockCallListener, Status.Code.INTERNAL, panicReason); + panicExpected = true; + } + private void verifyPanicMode(Throwable cause) { panicExpected = true; @SuppressWarnings("unchecked")