diff --git a/core/src/main/java/io/grpc/internal/InternalSubchannel.java b/core/src/main/java/io/grpc/internal/InternalSubchannel.java index 9a7822aa1c..d947452866 100644 --- a/core/src/main/java/io/grpc/internal/InternalSubchannel.java +++ b/core/src/main/java/io/grpc/internal/InternalSubchannel.java @@ -494,6 +494,7 @@ final class InternalSubchannel implements InternalInstrumented, Tr private class TransportListener implements ManagedClientTransport.Listener { final ConnectionClientTransport transport; final SocketAddress address; + boolean shutdownInitiated = false; TransportListener(ConnectionClientTransport transport, SocketAddress address) { this.transport = transport; @@ -530,6 +531,7 @@ final class InternalSubchannel implements InternalInstrumented, Tr public void transportShutdown(final Status s) { channelLogger.log( ChannelLogLevel.INFO, "{0} SHUTDOWN with {1}", transport.getLogId(), printShortStatus(s)); + shutdownInitiated = true; syncContext.execute(new Runnable() { @Override public void run() { @@ -561,6 +563,9 @@ final class InternalSubchannel implements InternalInstrumented, Tr @Override public void transportTerminated() { + Preconditions.checkState( + shutdownInitiated, "transportShutdown() must be called before transportTerminated()."); + channelLogger.log(ChannelLogLevel.INFO, "{0} Terminated", transport.getLogId()); channelz.removeClientSocket(transport); handleTransportInUseState(transport, false); @@ -573,9 +578,6 @@ final class InternalSubchannel implements InternalInstrumented, Tr } } }); - Preconditions.checkState(activeTransport != transport, - "activeTransport still points to this transport. " - + "Seems transportShutdown() was not called."); } } diff --git a/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java b/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java index f36ebd2196..4d942954b9 100644 --- a/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java +++ b/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java @@ -839,6 +839,7 @@ public class InternalSubchannelTest { internalSubchannel.shutdown(SHUTDOWN_REASON); verify(transportInfo.transport).shutdown(same(SHUTDOWN_REASON)); assertExactCallbackInvokes("onStateChange:SHUTDOWN"); + transportInfo.listener.transportShutdown(SHUTDOWN_REASON); transportInfo.listener.transportTerminated(); assertExactCallbackInvokes("onTerminated"); @@ -1144,7 +1145,9 @@ public class InternalSubchannelTest { internalSubchannel.obtainActiveTransport(); MockClientTransportInfo t0 = transports.poll(); + t0.listener.transportReady(); assertTrue(channelz.containsClientSocket(t0.transport.getLogId())); + t0.listener.transportShutdown(Status.RESOURCE_EXHAUSTED); t0.listener.transportTerminated(); assertFalse(channelz.containsClientSocket(t0.transport.getLogId())); } diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index b9b5ac3c5b..3fb9dfea0b 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -521,8 +521,10 @@ public class ManagedChannelImplTest { MockClientTransportInfo transportInfo = transports.poll(); assertNotNull(transportInfo); assertTrue(channelz.containsClientSocket(transportInfo.transport.getLogId())); + transportInfo.listener.transportReady(); // terminate transport + transportInfo.listener.transportShutdown(Status.CANCELLED); transportInfo.listener.transportTerminated(); assertFalse(channelz.containsClientSocket(transportInfo.transport.getLogId())); @@ -564,6 +566,7 @@ public class ManagedChannelImplTest { assertTrue(channelz.containsClientSocket(transportInfo.transport.getLogId())); // terminate transport + transportInfo.listener.transportShutdown(Status.INTERNAL); transportInfo.listener.transportTerminated(); assertFalse(channelz.containsClientSocket(transportInfo.transport.getLogId())); @@ -3270,6 +3273,7 @@ public class ManagedChannelImplTest { verify(mockLoadBalancer).shutdown(); // simulating the shutdown of load balancer triggers the shutdown of subchannel shutdownSafely(helper, subchannel); + transportInfo.listener.transportShutdown(Status.INTERNAL); transportInfo.listener.transportTerminated(); // simulating transport terminated assertTrue( "channel.isTerminated() is expected to be true but was false", @@ -3369,7 +3373,9 @@ public class ManagedChannelImplTest { verify(mockLoadBalancer).shutdown(); // simulating the shutdown of load balancer triggers the shutdown of subchannel shutdownSafely(helper, subchannel); - transportInfo.listener.transportTerminated(); // simulating transport terminated + // simulating transport shutdown & terminated + transportInfo.listener.transportShutdown(Status.INTERNAL); + transportInfo.listener.transportTerminated(); assertTrue( "channel.isTerminated() is expected to be true but was false", channel.isTerminated());