protected void submitResponse(RestRequest restRequest, RestResponseChannel restResponseChannel,
      ReadableStreamChannel response, Exception exception) throws RestServiceException {
    long processingStartTime = System.currentTimeMillis();
    if (restRequest == null || restResponseChannel == null) {
      throw new IllegalArgumentException("Received one or more null arguments");
    }
    try {
      metrics.responseArrivalRate.mark();
      if (exception != null || response == null) {
        onResponseComplete(restRequest, restResponseChannel, response, exception);
      } else {
        ResponseWriteCallback responseWriteCallback =
            new ResponseWriteCallback(restRequest, response, restResponseChannel);
        if (responses.putIfAbsent(restRequest, responseWriteCallback) != null) {
          metrics.responseAlreadyInFlightError.inc();
          throw new RestServiceException("Request for which response is being scheduled has a response outstanding",
              RestServiceErrorCode.RequestResponseQueuingFailure);
        } else {
          response.readInto(restResponseChannel, responseWriteCallback);
          inFlightResponsesCount.incrementAndGet();
          logger.trace("Response of size {} for request {} is scheduled to be sent", response.getSize(),
              restRequest.getUri());
        }
      }
    } finally {
      long preProcessingTime = System.currentTimeMillis() - processingStartTime;
      metrics.responsePreProcessingTimeInMs.update(preProcessingTime);
      restRequest.getMetricsTracker().scalingMetricsTracker.addToResponseProcessingTime(preProcessingTime);
    }
  }
Handles response sending asynchronously. When this function returns, it may not be sent yet.
@param restRequest the {@link RestRequest} for which the response has been constructed.
@param restResponseChannel the {@link RestResponseChannel} to be used to send the response.
@param response a {@link ReadableStreamChannel} that represents the response to the {@code restRequest}.
@param exception if the response could not be constructed, the reason for the failure.
@throws IllegalArgumentException if either of {@code restRequest} or {@code restResponseChannel} is null.
@throws RestServiceException if there is any error while processing the response.
ambry-rest/src/main/java/com/github/ambry/rest/AsyncRequestResponseHandler.java