NettyClientHandler extends AbstractNettyHandler { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { try { logger.fine("Network channel is closed"); lifecycleManager.notifyShutdown( Status.UNAVAILABLE.withDescription("Network closed for unknown reason")); cancelPing(lifecycleManager.getShutdownThrowable()); connection().forEachActiveStream(new Http2StreamVisitor() { @Override public boolean visit(Http2Stream stream) throws Http2Exception { NettyClientStream clientStream = clientStream(stream); if (clientStream != null) { clientStream.transportReportStatus( lifecycleManager.getShutdownStatus(), false, new Metadata()); } return true; } }); } finally { super.channelInactive(ctx); } } private  NettyClientHandler(Http2ConnectionDecoder decoder,
                             StreamBufferingEncoder encoder, Http2Settings settings,
                             ClientTransportLifecycleManager lifecycleManager,
                             Ticker ticker); @Override void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise); @Override void close(ChannelHandlerContext ctx, ChannelPromise promise); @Override void channelInactive(ChannelHandlerContext ctx);  }
@Test public void channelShutdownShouldCancelBufferedStreams() throws Exception { receiveMaxConcurrentStreams(0); ChannelFuture future = enqueue(new CreateStreamCommand(grpcHeaders, stream)); handler().channelInactive(ctx()); assertTrue(future.isDone()); assertFalse(future.isSuccess()); }
@Test public void ping_failsWhenChannelCloses() throws Exception { PingCallbackImpl callback = new PingCallbackImpl(); sendPing(callback); assertEquals(0, callback.invocationCount); handler().channelInactive(ctx()); assertEquals(1, callback.invocationCount); assertTrue(callback.failureCause instanceof StatusException); assertEquals(Status.Code.UNAVAILABLE, ((StatusException) callback.failureCause).getStatus().getCode()); }