@Override
  public void onResponseComplete(Exception exception) {
    long responseCompleteStartTime = System.currentTimeMillis();
    try {
      if (responseCompleteCalled.compareAndSet(false, true)) {
        logger.trace("Finished responding to current request on channel {}", ctx.channel());
        nettyMetrics.requestCompletionRate.mark();
        if (exception == null) {
          if (!maybeWriteResponseMetadata(responseMetadata, new ResponseMetadataWriteListener())) {
            // There were other writes. Let ChunkedWriteHandler finish if it has been kicked off.
            chunkedWriteHandler.resumeTransfer();
          }
        } else {
          log(exception);
          if (request != null) {
            request.getMetricsTracker().markFailure();
          }
          // need to set writeFuture as failed in case writes have started or chunks have been queued.
          if (!writeFuture.isDone()) {
            writeFuture.setFailure(exception);
          }
          if (!maybeSendErrorResponse(exception)) {
            completeRequest(true, true, true);
          }
        }
      } else if (exception != null) {
        // this is probably an attempt to force close the channel *after* the response is already complete.
        log(exception);
        if (!writeFuture.isDone()) {
          writeFuture.setFailure(exception);
        }
        completeRequest(true, true, true);
      }
      long responseFinishProcessingTime = System.currentTimeMillis() - responseCompleteStartTime;
      nettyMetrics.responseFinishProcessingTimeInMs.update(responseFinishProcessingTime);
      if (request != null) {
        request.getMetricsTracker().nioMetricsTracker.addToResponseProcessingTime(responseFinishProcessingTime);
      }
    } catch (Exception e) {
      logger.error("Swallowing exception encountered during onResponseComplete tasks", e);
      nettyMetrics.responseCompleteTasksError.inc();
      if (!writeFuture.isDone()) {
        writeFuture.setFailure(exception);
      }
      completeRequest(true, true, true);
    }
  }
{@inheritDoc}
<p/>
Marks the channel as closed. No further communication will be possible. Any pending writes (that are not already
flushed) might be discarded. The process of closing the network channel is also initiated.
<p/>
The underlying network channel might not be closed immediately but no more writes will be accepted and any calls to
{@link #isOpen()} after a call to this function will return {@code false}.
ambry-rest/src/main/java/com/github/ambry/rest/NettyResponseChannel.java