private void handleChannelWriteFailure(Throwable cause, boolean propagateErrorIfRequired) {
    long writeFailureProcessingStartTime = System.currentTimeMillis();
    try {
      nettyMetrics.channelWriteError.inc();
      Exception exception;
      if (!(cause instanceof Exception)) {
        logger.warn("Encountered a throwable on channel write failure", cause);
        exception = new IllegalStateException("Encountered a Throwable - " + cause.getMessage());
        if (propagateErrorIfRequired) {
          // we can't ignore throwables - so we let Netty deal with it.
          ctx.fireExceptionCaught(cause);
          nettyMetrics.throwableCount.inc();
        }
      } else if (cause instanceof ClosedChannelException) {
        // wrap the exception in something we recognize as a client termination
        exception = Utils.convertToClientTerminationException(cause);
      } else {
        exception = (Exception) cause;
      }
      onResponseComplete(exception);
      cleanupChunks(exception);
    } finally {
      nettyMetrics.channelWriteFailureProcessingTimeInMs.update(
          System.currentTimeMillis() - writeFailureProcessingStartTime);
    }
  }
Handles post-mortem of writes that have failed.
@param cause the cause of the failure.
@param propagateErrorIfRequired if {@code true} and {@code cause} is not an instance of {@link Exception}, the
                                error is propagated through the netty pipeline.
ambry-rest/src/main/java/com/github/ambry/rest/NettyResponseChannel.java