void handleResponse(ResponseInfo responseInfo) {
    long startTime = time.milliseconds();
    ReplicateBlobResponse replicateBlobResponse =
        RouterUtils.extractResponseAndNotifyResponseHandler(responseHandler, routerMetrics, responseInfo,
            ReplicateBlobResponse::readFrom, ReplicateBlobResponse::getError);
    RequestInfo routerRequestInfo = responseInfo.getRequestInfo();
    int correlationId = routerRequestInfo.getRequest().getCorrelationId();
    ReplicateBlobOperation replicateBlobOperation = correlationIdToReplicateBlobOperation.remove(correlationId);
    // If it is still an active operation, hand over the response. Otherwise, ignore.
    if (replicateBlobOperations.contains(replicateBlobOperation)) {
      boolean exceptionEncountered = false;
      try {
        replicateBlobOperation.handleResponse(responseInfo, replicateBlobResponse);
      } catch (Exception e) {
        exceptionEncountered = true;
        replicateBlobOperation.setOperationException(
            new RouterException("ReplicateBlob handleResponse encountered unexpected error", e,
                RouterErrorCode.UnexpectedInternalError));
      }
      if (exceptionEncountered || replicateBlobOperation.isOperationComplete()) {
        if (replicateBlobOperations.remove(replicateBlobOperation)) {
          onComplete(replicateBlobOperation);
        }
      }
      routerMetrics.replicateBlobManagerHandleResponseTimeMs.update(time.milliseconds() - startTime);
    } else {
      routerMetrics.ignoredResponseCount.inc();
    }
  }
Handles responses received for each of the {@link ReplicateBlobOperation} within this ReplicateBlob manager.
@param responseInfo the {@link ResponseInfo} containing the response.
ambry-router/src/main/java/com/github/ambry/router/ReplicateBlobManager.java