@Override
    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Channel inactive: {}", channel);
        }
        final Exception e = new SofaRpcException(RpcErrorType.CLIENT_NETWORK, "Channel "
            + NetUtils.channelToString(channel.localAddress(), channel.remoteAddress())
            + " has been closed, remove future when channel inactive.");
        Iterator<Entry<Integer, Entry<ChannelFuture, AbstractHttpClientHandler>>> it =
                streamIdPromiseMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Integer, Entry<ChannelFuture, AbstractHttpClientHandler>> mapEntry = it.next();
            it.remove();
            Entry<ChannelFuture, AbstractHttpClientHandler> entry = mapEntry.getValue();
            entry.getValue().onException(e);
        }
    }
Create an association between an anticipated response stream id and a {@link ChannelPromise}

@param streamId    The stream for which a response is expected
@param writeFuture A future that represent the request write operation
@param promise     The promise object that will be used to wait/notify events
@return The previous object associated with {@code streamId}
remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/http/Http2ClientChannelHandler.java