private void checkAndMaybeComplete() {
    // operationCompleted is true if Blob_Authorization_Failure was received.
    if (operationTracker.isDone() || operationCompleted) {
      if (operationTracker.hasSucceeded()) {
        operationException.set(null);
      } else {
        if (enableForceDeleteInRequest) {
          // We don't expect force delete to fail. Something is not right with servers
          logger.error("ForceDelete : failed to force delete blob {}", blobId, operationException.get());
          routerMetrics.forceDeleteBlobErrorCount.inc();
        }
        // the operation is failed, try to recover with ReplicateBlob
        if (shouldReplicateBlobAndRetry()) {
          // if retryWithReplicateBlob returns true, it's under retry. operation is not completed yet. so return.
          // if it returns false, continue the following code to set the proper operationException and complete the request.
          if (retryWithReplicateBlob()) {
            return;
          }
        }

        if (operationTracker.hasFailedOnNotFound()) {
          operationException.set(
              new RouterException("DeleteOperation failed because of BlobNotFound", RouterErrorCode.BlobDoesNotExist));
        } else if (operationTracker.hasSomeUnavailability()) {
          setOperationException(
              new RouterException("DeleteOperation failed possibly because some replicas are unavailable",
                  RouterErrorCode.AmbryUnavailable));
        }

        // check if we want to record the partially failed request and repair in the background.
        if (shouldRunOfflineRepair()) {
          RepairRequestRecord record = null;
          try {
            List<ReplicaId> successfulReplica = operationTracker.getSuccessReplica();
            DataNodeId sourceDataNode = successfulReplica.get(0).getDataNodeId();
            record =
                new RepairRequestRecord(blobId.getID(), blobId.getPartition().getId(), sourceDataNode.getHostname(),
                    sourceDataNode.getPort(), RepairRequestRecord.OperationType.DeleteRequest, deletionTimeMs,
                    LIFE_VERSION_FROM_FRONTEND, Utils.Infinite_Time);
            repairRequestsDb.putRepairRequests(record);

            // treat the delete command as a success
            operationException.set(null);
            routerMetrics.offlineRepairOnDeleteCount.inc();
            logger.info("RepairRequest : inject repair request {} to the database {}", record, repairRequestsDb);
          } catch (Exception e) {
            routerMetrics.offlineRepairOnDeleteErrorCount.inc();
            logger.error("RepairRequest : failed to write the {} to the database {}", record, repairRequestsDb);
          }
        }

        // Handle the exceptions of the background deleter
        if (isServiceBackgroundDeleter() && operationException.get() != null) {
          RouterErrorCode code = ((RouterException) operationException.get()).getErrorCode();
          if (code == RouterErrorCode.BlobDoesNotExist) {
            // NOT_FOUND is not an error for the background deleter.
            routerMetrics.backgroundDeleterNotFoundCount.inc();
            logger.info("Ignore BlobNotFound error from the background deleter. {}", blobId);
          } else {
            // We may hit AmbryUnavailable or other exceptions.
            // Since we don't do any further thing for it anyway, swallow the exception.
            // Just emit with metrics and log error message
            routerMetrics.backgroundDeleterExceptionCount.inc();
            logger.error("Background deleter hit exception {} {}", blobId, code);
          }
          operationException.set(null);
        }

        // Check if we should issue force delete for this operation.
        // enableForceDeleteInRequest by default is false, it will be set to true only once here, which means, if it's
        // already true, then we already enabled force delete but somehow it still failed.
        if (!enableForceDeleteInRequest && shouldIssueForceDelete()) {
          // Retry this delete operation with force delete
          logger.info("Enabling force delete for blob: {}", blobId);
          routerMetrics.forceDeleteBlobCount.inc();
          enableForceDeleteInRequest = true;
          // Reset the operation exception and the operation tracker
          // Next time if we call operationTracker.isDone, it will return false. And it only returns true when force delete
          // finishes.
          operationException.set(null);
          operationTracker =
              new SimpleOperationTracker(routerConfig, RouterOperation.DeleteOperation, blobId.getPartition(),
                  originatingDcName, false, routerMetrics, blobId);
          deleteRequestInfos.clear();
          // return here, so we don't have to change quota or set the operationCompleted to true.
          return;
        }
      }
      if (QuotaUtils.postProcessCharge(quotaChargeCallback)) {
        try {
          quotaChargeCallback.checkAndCharge(false, true);
        } catch (QuotaException quotaException) {
          logger.error("Exception  {} in quota charge event listener during delete operation",
              quotaException.toString());
        }
      }
      operationCompleted = true;
    }
  }
Completes the {@code DeleteOperation} if it is done.
ambry-router/src/main/java/com/github/ambry/router/DeleteOperation.java