All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cloudfoundry.multiapps.controller.process.jobs.OperationsCleaner Maven / Gradle / Ivy

There is a newer version: 1.183.0
Show newest version
package org.cloudfoundry.multiapps.controller.process.jobs;

import static java.text.MessageFormat.format;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.List;

import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.cloudfoundry.multiapps.controller.api.model.ImmutableOperation;
import org.cloudfoundry.multiapps.controller.api.model.Operation;
import org.cloudfoundry.multiapps.controller.persistence.OrderDirection;
import org.cloudfoundry.multiapps.controller.persistence.services.OperationService;
import org.cloudfoundry.multiapps.controller.process.Messages;
import org.cloudfoundry.multiapps.controller.process.flowable.Action;
import org.cloudfoundry.multiapps.controller.process.flowable.ProcessAction;
import org.cloudfoundry.multiapps.controller.process.flowable.ProcessActionRegistry;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;

@Named
@Order(10)
public class OperationsCleaner implements Cleaner {

    private static final Logger LOGGER = LoggerFactory.getLogger(OperationsCleaner.class);
    private static final int DEFAULT_PAGE_SIZE = 100;

    private final OperationService operationService;
    private final ProcessActionRegistry processActionRegistry;
    private int pageSize = DEFAULT_PAGE_SIZE;

    @Inject
    public OperationsCleaner(OperationService operationService, ProcessActionRegistry processActionRegistry) {
        this.operationService = operationService;
        this.processActionRegistry = processActionRegistry;
    }

    public OperationsCleaner withPageSize(int pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    @Override
    public void execute(LocalDateTime expirationTime) {
        LOGGER.debug(CleanUpJob.LOG_MARKER, format(Messages.DELETING_OPERATIONS_STARTED_BEFORE_0, expirationTime));
        int abortedOperations = abortActiveOperations(expirationTime);
        LOGGER.info(CleanUpJob.LOG_MARKER, format(Messages.ABORTED_OPERATIONS_0, abortedOperations));
        int deletedOperations = operationService.createQuery()
                                                .startedBefore(expirationTime)
                                                .inFinalState()
                                                .delete();
        LOGGER.info(CleanUpJob.LOG_MARKER, format(Messages.DELETED_OPERATIONS_0, deletedOperations));
    }

    private int abortActiveOperations(LocalDateTime expirationTime) {
        int abortedOperations = 0;
        for (int pageIndex = 0;; pageIndex++) {
            List operationsPage = getOperationsPage(expirationTime, pageIndex);
            for (Operation operation : operationsPage) {
                if (inFinalState(operation)) {
                    continue;
                }
                boolean abortWasSuccessful = abortSafely(operation);
                if (abortWasSuccessful) {
                    abortedOperations++;
                }
            }
            if (pageSize > operationsPage.size()) {
                return abortedOperations;
            }
        }
    }

    private List getOperationsPage(LocalDateTime expirationTime, int pageIndex) {
        return operationService.createQuery()
                               .startedBefore(expirationTime)
                               .offsetOnSelect(pageIndex * pageSize)
                               .limitOnSelect(pageSize)
                               .orderByProcessId(OrderDirection.ASCENDING)
                               .list();
    }

    private boolean inFinalState(Operation operation) {
        return operation.getState()
                        .isFinal();
    }

    private boolean abortSafely(Operation operation) {
        try {
            abort(operation);
            return true;
        } catch (FlowableObjectNotFoundException e) {
            abortOrphanedOperation(operation);
            return true;
        } catch (Exception e) {
            LOGGER.warn(CleanUpJob.LOG_MARKER, format(Messages.COULD_NOT_ABORT_OPERATION_0, operation.getProcessId()), e);
            return false;
        }
    }

    private void abort(Operation operation) {
        ProcessAction abortAction = processActionRegistry.getAction(Action.ABORT);
        String processId = operation.getProcessId();
        LOGGER.debug(CleanUpJob.LOG_MARKER, format(Messages.ABORTING_OPERATION_0, processId));
        abortAction.execute(null, processId);
    }

    private void abortOrphanedOperation(Operation operation) {
        Operation abortedOperation = ImmutableOperation.builder()
                                                       .from(operation)
                                                       .state(Operation.State.ABORTED)
                                                       .endedAt(ZonedDateTime.now())
                                                       .hasAcquiredLock(false)
                                                       .build();
        operationService.update(operation, abortedOperation);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy