@Override
    public void operationComplete(ChannelFuture future) {
      long writeFinishTime = System.currentTimeMillis();
      if (future.isSuccess()) {
        if (finalResponseMetadata instanceof LastHttpContent) {
          // this is the case if finalResponseMetadata is a FullHttpResponse.
          // in this case there is nothing more to write.
          if (!writeFuture.isDone()) {
            writeFuture.setSuccess();
            //Don't close the request when we see 100-continue in EXPECT header.
            completeRequest(!HttpUtil.isKeepAlive(finalResponseMetadata), false,
                !(nettyConfig.nettyEnableOneHundredContinue
                    && RestUtils.isPutOrPostS3RequestAndExpectContinue(request)));
          }
        } else {
          // otherwise there is some content to write.
          logger.trace("Starting ChunkedWriteHandler on channel {}", ctx.channel());
          writeFuture.addListener(new CallbackInvoker());
          ctx.writeAndFlush(new ChunkDispenser(), writeFuture);
        }
      } else {
        handleChannelWriteFailure(future.cause(), true);
      }
      long responseAfterWriteProcessingTime = System.currentTimeMillis() - writeFinishTime;
      long channelWriteTime = writeFinishTime - responseWriteStartTime;
      nettyMetrics.channelWriteTimeInMs.update(channelWriteTime);
      nettyMetrics.responseMetadataAfterWriteProcessingTimeInMs.update(responseAfterWriteProcessingTime);
      if (request != null) {
        request.getMetricsTracker().nioMetricsTracker.addToResponseProcessingTime(
            channelWriteTime + responseAfterWriteProcessingTime);
      }
    }
If the operation completed successfully, a write via the {@link ChunkedWriteHandler} is initiated. Otherwise,
failure is handled.
@param future the {@link ChannelFuture} that is being listened on.
ambry-rest/src/main/java/com/github/ambry/rest/NettyResponseChannel.java