protected void deleteBlob(final String blobIdStr, final String serviceId, FutureResult<Void> futureResult,
      final Callback<Void> callback, boolean attemptChunkDeletes, QuotaChargeCallback quotaChargeCallback) {
    try {
      deleteManager.submitDeleteBlobOperation(blobIdStr, serviceId, futureResult,
          (Void result, Exception exception) -> {
            if (exception == null && attemptChunkDeletes) {
              try {
                nonBlockingRouter.initiateChunkDeletesIfAny(blobIdStr, serviceId, quotaChargeCallback);
              } catch (RouterException e) {
                logger.warn(
                    "RouterException for same reason should have been thrown by submitDeleteBlobOperation() and no callback should be triggered.",
                    e);
              }
            }
            if (callback != null) {
              callback.onCompletion(result, exception);
            }
          }, quotaChargeCallback);
    } catch (RouterException e) {
      routerMetrics.operationDequeuingRate.mark();
      routerMetrics.onDeleteBlobError(e);
      nonBlockingRouter.completeOperation(futureResult, callback, null, e);
    }
    routerCallback.onPollReady();
  }
Requests for a blob to be deleted asynchronously and invokes the {@link Callback} when the request completes.
@param blobIdStr The ID of the blob that needs to be deleted in string form
@param serviceId The service ID of the service deleting the blob. This can be null if unknown.
@param futureResult A future that would contain information about whether the deletion succeeded or not,
                    eventually.
@param callback The {@link Callback} which will be invoked on the completion of a request.
@param attemptChunkDeletes whether delete of chunks of the given blob (if it turns out to be composite) should be
                           attempted. Set this to false if it is known that the given blob is a data chunk.
ambry-router/src/main/java/com/github/ambry/router/OperationController.java