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

ru.taskurotta.service.storage.GeneralTaskService Maven / Gradle / Ivy

package ru.taskurotta.service.storage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.taskurotta.internal.core.ArgType;
import ru.taskurotta.internal.core.TaskType;
import ru.taskurotta.service.console.model.GenericPage;
import ru.taskurotta.service.console.retriever.TaskInfoRetriever;
import ru.taskurotta.service.console.retriever.command.TaskSearchCommand;
import ru.taskurotta.transport.model.ArgContainer;
import ru.taskurotta.transport.model.DecisionContainer;
import ru.taskurotta.transport.model.TaskContainer;
import ru.taskurotta.transport.model.TaskOptionsContainer;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

/**
 * User: romario
 * Date: 4/1/13
 * Time: 9:34 PM
 */
public class GeneralTaskService implements TaskService, TaskInfoRetriever {

    private final static Logger logger = LoggerFactory.getLogger(GeneralTaskService.class);

    private TaskDao taskDao;
    private long workerTimeoutMilliseconds;

    public GeneralTaskService(TaskDao taskDao, long workerTimeoutMilliseconds) {
        this.taskDao = taskDao;
        this.workerTimeoutMilliseconds = workerTimeoutMilliseconds;
    }

    @Override
    public void startProcess(TaskContainer taskContainer) {
        taskDao.addTask(taskContainer);
    }

    @Override
    public TaskContainer getTaskToExecute(UUID taskId, UUID processId, boolean simulate) {
        logger.debug("getTaskToExecute(taskId[{}], processId[{}]) started", taskId, processId);

        TaskContainer task = getTask(taskId, processId);

        // WARNING: "task" object is the same instance as In memory data storage. So we should use  it deep clone
        // due guarantees for its immutability.

        if (task == null) {
            logger.error("Inconsistent state, taskId[{}] does not present at task service", taskId);
            return null;
        }

        ArgContainer[] args = task.getArgs();

        if (args != null) {//updating ready Promises args into real values

            if (logger.isDebugEnabled()) {
                logger.debug("Task id[{}], type[{}], method[{}] args before swap processing [{}]", task.getTaskId(), task.getType(), task.getMethod(), Arrays.asList(args));
            }

            TaskOptionsContainer taskOptionsContainer = task.getOptions();
            ArgType[] argTypes = null;

            if (taskOptionsContainer != null) {
                argTypes = task.getOptions().getArgTypes();
            }

            for (int i = 0; i < args.length; i++) {
                ArgContainer arg = args[i];

                if (arg == null) {
                    continue;
                }

                ArgType argType = argTypes == null ? null : argTypes[i];

                // don't try to calculate @NoWait promise.
                // there are so many cases when it is really needed
                // and we can introduce new annotation to mark that promices
                // with new type, for example: NO_WAIT_TRY.
                if (argType == ArgType.NO_WAIT) {
                    continue;
                }

                if (arg.isPromise()) {
                    args[i] = processPromiseArgValue(arg, processId, task, argType);
                } else if (arg.isCollection()) {//can be collection of promises, case should be checked
                    ArgContainer[] compositeValue = arg.getCompositeValue();

                    if (compositeValue != null && compositeValue.length > 0) {
                        for (int j = 0; j < compositeValue.length; j++) {
                            ArgContainer innerArg = compositeValue[j];
                            if (innerArg.isPromise()) {
                                compositeValue[j] = processPromiseArgValue(innerArg, processId, task, argType);
                            }
                        }
                    }
                }
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Task id[{}], type[{}], method[{}] args after swap processing [{}]", task.getTaskId(), task.getType(), task.getMethod(), Arrays.asList(args));
            }
        }

        // todo: timeout should be calculated for every actor

        if (!simulate) {
            // todo: actors should support acceptLast and acceptFirst strategies depends of their needs
            UUID pass = taskDao.startTask(taskId, processId, System.currentTimeMillis() + workerTimeoutMilliseconds, false);

            if (pass == null) {
                logger.error("{}/{} Task can not be executed. It is already started or finished", taskId, processId);
                return null;
            }

            task.setPass(pass);
        }

        return task;
    }


    private ArgContainer processPromiseArgValue(ArgContainer pArg, UUID processId, TaskContainer task, ArgType argType) {

        // Only decider asynchronous methods can use Promise args, NOT start method
        boolean isDeciderAsynchronousTaskType = isDeciderAsynchronousTaskType(task.getType());

        if (pArg.isReady()) {    // Promise.asPromise() was used as an argument, so there is no taskValue, it is simply Promise wrapper for a worker
            logger.debug("Got initialized promise, switch it to value");
            return isDeciderAsynchronousTaskType ? pArg : pArg.updateType(false);              // simply strip of promise wrapper
        }

        UUID taskId = pArg.getTaskId();

        //try to find promise value obtained by its task result
        ArgContainer taskValue = null;

        try {
            taskValue = getTaskValue(taskId, processId, ArgType.NO_WAIT.equals(argType));
        } catch (IllegalStateException e) {
            throw new IllegalStateException("Not initialized promise before execute [" + task + "]", e);
        }

        // Task not completed yet and not initialized Promise is acceptable by Decider
        if (taskValue == null) {
            return pArg;
        }

        ArgContainer newArg = new ArgContainer(taskValue);
        if (isDeciderAsynchronousTaskType) {

            // set real value into promise for Decider tasks
            newArg.setPromise(true);
            newArg.setTaskId(taskId);
        } else {

            // swap promise with real value for Actor tasks
            newArg.setPromise(false);
        }

        return newArg;
    }

    private static boolean isDeciderAsynchronousTaskType(TaskType taskType) {
        return TaskType.DECIDER_ASYNCHRONOUS.equals(taskType);
    }

    /**
     * @return ArgContainer (even in case of null value result), null if it acceptable (isNoWait is true)
     * or throw IllegalArgumentException (id decision not found and isNoWait is false)
     */
    private ArgContainer getTaskValue(UUID taskId, UUID processId, boolean isNoWait) throws IllegalStateException {

        DecisionContainer taskDecision = taskDao.getDecision(taskId, processId);

        if (taskDecision == null) {
            if (isNoWait) {
                // value may be null for NoWait promises
                // leave it in peace...
                return null;
            }
            throw new IllegalStateException("Decision not found for not @NoWait task [" + taskId + "] processId [" +
                    processId + "]");
        }

        logger.debug("taskDecision of taskId [{}] is [{}]", taskId, taskDecision);

        ArgContainer result;

        if (taskDecision.containsError()) {
            result = taskDecision.getValue();
            result.setErrorContainer(taskDecision.getErrorContainer());
        } else {
            result = taskDecision.getValue();
            if (result != null && result.isPromise() && !result.isReady()) {
                logger.debug("getTaskValue([{}]) argContainer.isPromise() && !argContainer.isReady(). arg[{}]", taskId, result);

                result = getTaskValue(result.getTaskId(), processId, isNoWait);
            }
        }

        logger.debug("getTaskValue({}) returns argContainer = [{}]", taskId, result);
        return result;
    }


    @Override
    public TaskContainer getTask(UUID taskId, UUID processId) {
        TaskContainer task = taskDao.getTask(taskId, processId);
        logger.debug("Task received by uuid[{}], is[{}]", taskId, task);
        return task;
    }

    @Override
    public List findTasks(TaskSearchCommand command) {
        return taskDao.findTasks(command);
    }

    @Override
    public GenericPage listTasks(int pageNumber, int pageSize) {
        return taskDao.listTasks(pageNumber, pageSize);
    }

    @Override
    public Collection getRepeatedTasks(int iterationCount) {
        return taskDao.getRepeatedTasks(iterationCount);
    }

    @Override
    public Collection getProcessTasks(Collection processTaskIds, UUID processId) {
        Collection tasks = new LinkedList<>();

        for (UUID taskId : processTaskIds) {
            tasks.add(taskDao.getTask(taskId, processId));
        }

        return tasks;
    }

    @Override
    public boolean finishTask(DecisionContainer taskDecision) {
        logger.debug("finishTask() taskDecision [{}]", taskDecision);

        if (!taskDao.finishTask(taskDecision)) {
            return false;
        }

        // increment number of attempts for error tasks with retry policy
        if (taskDecision.containsError() && taskDecision.getRestartTime() != -1) {

            TaskContainer task = taskDao.getTask(taskDecision.getTaskId(), taskDecision.getProcessId());

            // TODO: should be optimized
            task.incrementErrorAttempts();
            taskDao.updateTask(task);
        }

        TaskContainer[] taskContainers = taskDecision.getTasks();
        if (taskContainers != null) {
            for (TaskContainer taskContainer : taskContainers) {
                taskDao.addTask(taskContainer);
            }
        }

        return true;
    }

    @Override
    public boolean retryTask(UUID taskId, UUID processId, long timeToStart) {
        return taskDao.retryTask(taskId, processId, timeToStart);
    }

    @Override
    public boolean restartTask(UUID taskId, UUID processId, long timeToStart, boolean force) {
        return taskDao.restartTask(taskId, processId, timeToStart, force);
    }

    @Override
    public DecisionContainer getDecision(UUID taskId, UUID processId) {
        return taskDao.getDecision(taskId, processId);
    }

    @Override
    public List getAllRunProcesses() {
        return null;
    }

    @Override
    public List getAllTaskDecisions(UUID processId) {
        return null;
    }

    @Override
    public void finishProcess(UUID processId, Collection finishedTaskIds) {
        taskDao.archiveProcessData(processId, finishedTaskIds);
    }

    @Override
    public void updateTaskDecision(DecisionContainer taskDecision) {
        taskDao.updateTaskDecision(taskDecision);
    }


    public boolean isTaskReleased(UUID taskId, UUID processId) {
        return taskDao.isTaskReleased(taskId, processId);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy