diff --git a/netty/src/main/java/io/grpc/netty/NettyClientHandler.java b/netty/src/main/java/io/grpc/netty/NettyClientHandler.java index a6929e6f81..0fd61a4ff5 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientHandler.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientHandler.java @@ -767,7 +767,7 @@ class NettyClientHandler extends AbstractNettyHandler { private void forcefulClose(final ChannelHandlerContext ctx, final ForcefulCloseCommand msg, ChannelPromise promise) throws Exception { - // close() already called by NettyClientTransport, so just need to clean up streams + ctx.close(); connection().forEachActiveStream(new Http2StreamVisitor() { @Override public boolean visit(Http2Stream stream) throws Http2Exception { diff --git a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java index 7c009340a4..5802bfe616 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java @@ -346,9 +346,6 @@ class NettyClientTransport implements ConnectionClientTransport { @Override public void run() { lifecycleManager.notifyShutdown(reason); - // Call close() directly since negotiation may not have completed, such that a write would - // be queued. - channel.close(); channel.write(new ForcefulCloseCommand(reason)); } }, true); diff --git a/netty/src/main/java/io/grpc/netty/WriteBufferingAndExceptionHandler.java b/netty/src/main/java/io/grpc/netty/WriteBufferingAndExceptionHandler.java index 60c48c733d..9521fc9388 100644 --- a/netty/src/main/java/io/grpc/netty/WriteBufferingAndExceptionHandler.java +++ b/netty/src/main/java/io/grpc/netty/WriteBufferingAndExceptionHandler.java @@ -124,6 +124,11 @@ final class WriteBufferingAndExceptionHandler extends ChannelDuplexHandler { promise.setFailure(failCause); ReferenceCountUtil.release(msg); } else { + if (msg instanceof GracefulCloseCommand || msg instanceof ForcefulCloseCommand) { + // No point in continuing negotiation + ctx.close(); + // Still enqueue the command in case the HTTP/2 handler is already on the pipeline + } bufferedWrites.add(new ChannelWrite(msg, promise)); } }