Search in sources :

Example 61 with WorkflowDef

use of com.netflix.conductor.common.metadata.workflow.WorkflowDef in project conductor by Netflix.

the class MetadataServiceImpl method updateWorkflowDef.

/**
 * @param workflowDefList Workflow definitions to be updated.
 */
@Service
public void updateWorkflowDef(List<WorkflowDef> workflowDefList) {
    for (WorkflowDef workflowDef : workflowDefList) {
        workflowDef.setUpdateTime(System.currentTimeMillis());
        metadataDAO.updateWorkflowDef(workflowDef);
    }
}
Also used : WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) Service(com.netflix.conductor.annotations.Service)

Example 62 with WorkflowDef

use of com.netflix.conductor.common.metadata.workflow.WorkflowDef in project conductor by Netflix.

the class WorkflowExecutor method updateParentWorkflow.

/**
 * Update parent Workflow based on Subworkflow state.
 * Updates the provided subWorkflowTask and/or parentWorkflow inplace, where applicable.
 * @param subWorkflowTask
 * @param subWorkflow
 * @param parentWorkflow
 * @return
 */
@VisibleForTesting
protected boolean updateParentWorkflow(Task subWorkflowTask, Workflow subWorkflow, Workflow parentWorkflow) {
    WorkflowDef parentDef = Optional.ofNullable(parentWorkflow.getWorkflowDefinition()).orElseGet(() -> metadataDAO.getWorkflowDef(parentWorkflow.getWorkflowName(), parentWorkflow.getWorkflowVersion()).orElseThrow(() -> new ApplicationException(NOT_FOUND, String.format("Unable to find parent workflow definition for %s", parentWorkflow.getWorkflowId()))));
    LOGGER.debug("Evaluating parent workflow: {} for sub-workflow: {}", subWorkflow.getParentWorkflowId(), subWorkflow.getWorkflowId());
    // On Subworkflow complete or terminate..
    if (subWorkflow.getStatus().isTerminal()) {
        if (parentWorkflow.getStatus().equals(WorkflowStatus.FAILED)) {
            String warningMsg = String.format("Not evaluating parent workflow: %s in FAILED state for subworkflow: %s in terminal state.", parentWorkflow.getWorkflowId(), subWorkflow.getWorkflowId());
            LOGGER.warn(warningMsg);
            return false;
        } else if (subWorkflowTask.getStatus().equals(IN_PROGRESS)) {
            LOGGER.debug("Subworkflow: {} is {}, updating parent workflow: {}", subWorkflow.getWorkflowId(), subWorkflow.getStatus().name(), parentWorkflow.getWorkflowId());
            executeSubworkflowTaskAndSyncData(subWorkflow, subWorkflowTask);
            return true;
        } else {
            LOGGER.warn("Unable to evaluate parent workflow: {} in status: {}, and subworkflow: {} in status: {}", parentWorkflow.getWorkflowId(), parentWorkflow.getStatus().name(), subWorkflow.getWorkflowId(), subWorkflow.getStatus().name());
        }
    } else {
        // On workflow retry or restart..
        if (parentWorkflow.getStatus().isTerminal() && subWorkflowTask.getStatus().isTerminal()) {
            LOGGER.debug("Subworkflow: {} is {}, resetting failed parent workflow: {}, and Subworkflow task: {} status to IN_PROGRESS", subWorkflow.getWorkflowId(), subWorkflow.getStatus().name(), parentWorkflow.getWorkflowId(), subWorkflow.getParentWorkflowTaskId());
            subWorkflowTask.setStatus(IN_PROGRESS);
            executionDAOFacade.updateTask(subWorkflowTask);
            parentWorkflow.setStatus(WorkflowStatus.RUNNING);
            parentWorkflow.setLastRetriedTime(System.currentTimeMillis());
            executionDAOFacade.updateWorkflow(parentWorkflow);
            return true;
        } else if (parentWorkflow.getStatus().equals(WorkflowStatus.RUNNING)) {
            if (subWorkflowTask.getStatus().isTerminal()) {
                String errorMsg = String.format("Subworkflow: %s is in RUNNING state, but Subworkflow task: %s in parent workflow: %s is in FAILED state.", subWorkflow.getWorkflowId(), subWorkflowTask.getTaskId(), parentWorkflow.getWorkflowId());
                LOGGER.warn(errorMsg);
                throw new IllegalStateException(errorMsg);
            } else {
                // parentWorkflow, subWorkflowTask and subWorkflow are in non-terminal state
                return false;
            }
        } else {
            LOGGER.warn("Unable to evaluate parent workflow: {} in status: {}, and subworkflow: {} in status: {}", parentWorkflow.getWorkflowId(), parentWorkflow.getStatus().name(), subWorkflow.getWorkflowId(), subWorkflow.getStatus().name());
        }
    }
    return false;
}
Also used : WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 63 with WorkflowDef

use of com.netflix.conductor.common.metadata.workflow.WorkflowDef in project conductor by Netflix.

the class WorkflowExecutor method rewind.

/**
 * @param workflowId           the id of the workflow to be restarted
 * @param useLatestDefinitions if true, use the latest workflow and task definitions upon restart
 * @throws ApplicationException in the following cases:
 *                              <ul>
 *                              <li>Workflow is not in a terminal state</li>
 *                              <li>Workflow definition is not found</li>
 *                              <li>Workflow is deemed non-restartable as per workflow definition</li>
 *                              </ul>
 */
public void rewind(String workflowId, boolean useLatestDefinitions) {
    Workflow workflow = executionDAOFacade.getWorkflowById(workflowId, true);
    if (!workflow.getStatus().isTerminal()) {
        String errorMsg = String.format("Workflow: %s is not in terminal state, unable to restart.", workflow);
        LOGGER.error(errorMsg);
        throw new ApplicationException(CONFLICT, errorMsg);
    }
    WorkflowDef workflowDef;
    if (useLatestDefinitions) {
        workflowDef = metadataDAO.getLatestWorkflowDef(workflow.getWorkflowName()).orElseThrow(() -> new ApplicationException(NOT_FOUND, String.format("Unable to find latest definition for %s", workflowId)));
        // setting this here to ensure backward compatibility and consistency for workflows without the embedded workflow definition
        workflow.setVersion(workflowDef.getVersion());
        workflow.setWorkflowDefinition(workflowDef);
    } else {
        workflowDef = Optional.ofNullable(workflow.getWorkflowDefinition()).orElseGet(() -> metadataDAO.getWorkflowDef(workflow.getWorkflowName(), workflow.getWorkflowVersion()).orElseThrow(() -> new ApplicationException(NOT_FOUND, String.format("Unable to find definition for %s", workflowId))));
    }
    if (!workflowDef.isRestartable() && workflow.getStatus().equals(WorkflowStatus.COMPLETED)) {
        // Can only restart non-completed workflows when the configuration is set to false
        throw new ApplicationException(CONFLICT, String.format("Workflow: %s is non-restartable", workflow));
    }
    // Reset the workflow in the primary datastore and remove from indexer; then re-create it
    executionDAOFacade.resetWorkflow(workflowId);
    workflow.getTasks().clear();
    workflow.setReasonForIncompletion(null);
    workflow.setStartTime(System.currentTimeMillis());
    workflow.setEndTime(0);
    // Change the status to running
    workflow.setStatus(WorkflowStatus.RUNNING);
    workflow.setOutput(null);
    workflow.setExternalOutputPayloadStoragePath(null);
    try {
        executionDAOFacade.createWorkflow(workflow);
    } catch (Exception e) {
        Monitors.recordWorkflowStartError(workflowDef.getName(), WorkflowContext.get().getClientApp());
        LOGGER.error("Unable to restart workflow: {}", workflowDef.getName(), e);
        terminateWorkflow(workflowId, "Error when restarting the workflow");
        throw e;
    }
    decide(workflowId);
    if (StringUtils.isNotEmpty(workflow.getParentWorkflowId())) {
        updateParentWorkflow(workflow);
        decide(workflow.getParentWorkflowId());
    }
}
Also used : WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) SubWorkflow(com.netflix.conductor.core.execution.tasks.SubWorkflow) Workflow(com.netflix.conductor.common.run.Workflow)

Example 64 with WorkflowDef

use of com.netflix.conductor.common.metadata.workflow.WorkflowDef in project conductor by Netflix.

the class DeciderService method checkWorkflowTimeout.

@VisibleForTesting
void checkWorkflowTimeout(Workflow workflow) {
    WorkflowDef workflowDef = workflow.getWorkflowDefinition();
    if (workflowDef == null) {
        LOGGER.warn("Missing workflow definition : {}", workflow.getWorkflowId());
        return;
    }
    if (workflow.getStatus().isTerminal() || workflowDef.getTimeoutSeconds() <= 0) {
        return;
    }
    long timeout = 1000L * workflowDef.getTimeoutSeconds();
    long now = System.currentTimeMillis();
    long elapsedTime = workflow.getLastRetriedTime() > 0 ? now - workflow.getLastRetriedTime() : now - workflow.getStartTime();
    if (elapsedTime < timeout) {
        return;
    }
    String reason = String.format("Workflow '%s' timed out after %d seconds. Timeout configured as %d. " + "Timeout policy configured to %s", workflow.getWorkflowId(), elapsedTime / 1000L, timeout, workflowDef.getTimeoutPolicy().name());
    switch(workflowDef.getTimeoutPolicy()) {
        case ALERT_ONLY:
            LOGGER.info(reason);
            Monitors.recordWorkflowTermination(workflow.getWorkflowName(), WorkflowStatus.TIMED_OUT, workflow.getOwnerApp());
            return;
        case TIME_OUT_WF:
            throw new TerminateWorkflowException(reason, WorkflowStatus.TIMED_OUT);
    }
}
Also used : WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 65 with WorkflowDef

use of com.netflix.conductor.common.metadata.workflow.WorkflowDef in project conductor by Netflix.

the class DeciderService method startWorkflow.

private List<Task> startWorkflow(Workflow workflow) throws TerminateWorkflowException {
    final WorkflowDef workflowDef = workflow.getWorkflowDefinition();
    LOGGER.debug("Starting workflow: {}", workflow);
    // The tasks will be empty in case of new workflow
    List<Task> tasks = workflow.getTasks();
    // Check if the workflow is a re-run case or if it is a new workflow execution
    if (workflow.getReRunFromWorkflowId() == null || tasks.isEmpty()) {
        if (workflowDef.getTasks().isEmpty()) {
            throw new TerminateWorkflowException("No tasks found to be executed", WorkflowStatus.COMPLETED);
        }
        // Nothing is running yet - so schedule the first task
        WorkflowTask taskToSchedule = workflowDef.getTasks().get(0);
        // Loop until a non-skipped task is found
        while (isTaskSkipped(taskToSchedule, workflow)) {
            taskToSchedule = workflowDef.getNextTask(taskToSchedule.getTaskReferenceName());
        }
        // In case of a new workflow, the first non-skippable task will be scheduled
        return getTasksToBeScheduled(workflow, taskToSchedule, 0);
    }
    // Get the first task to schedule
    Task rerunFromTask = tasks.stream().findFirst().map(task -> {
        task.setStatus(SCHEDULED);
        task.setRetried(true);
        task.setRetryCount(0);
        return task;
    }).orElseThrow(() -> {
        String reason = String.format("The workflow %s is marked for re-run from %s but could not find the starting task", workflow.getWorkflowId(), workflow.getReRunFromWorkflowId());
        return new TerminateWorkflowException(reason);
    });
    return Collections.singletonList(rerunFromTask);
}
Also used : TaskUtils(com.netflix.conductor.common.utils.TaskUtils) TaskMapper(com.netflix.conductor.core.execution.mapper.TaskMapper) IDGenerator(com.netflix.conductor.core.utils.IDGenerator) Status(com.netflix.conductor.common.metadata.tasks.Task.Status) LoggerFactory(org.slf4j.LoggerFactory) TaskMapperContext(com.netflix.conductor.core.execution.mapper.TaskMapperContext) HashMap(java.util.HashMap) MetadataDAO(com.netflix.conductor.dao.MetadataDAO) Task(com.netflix.conductor.common.metadata.tasks.Task) StringUtils(org.apache.commons.lang3.StringUtils) LinkedHashMap(java.util.LinkedHashMap) Inject(javax.inject.Inject) SUB_WORKFLOW(com.netflix.conductor.common.metadata.workflow.TaskType.SUB_WORKFLOW) COMPLETED_WITH_ERRORS(com.netflix.conductor.common.metadata.tasks.Task.Status.COMPLETED_WITH_ERRORS) ExternalPayloadStorageUtils(com.netflix.conductor.core.utils.ExternalPayloadStorageUtils) Workflow(com.netflix.conductor.common.run.Workflow) IN_PROGRESS(com.netflix.conductor.common.metadata.tasks.Task.Status.IN_PROGRESS) Map(java.util.Map) SKIPPED(com.netflix.conductor.common.metadata.tasks.Task.Status.SKIPPED) Operation(com.netflix.conductor.common.utils.ExternalPayloadStorage.Operation) Named(javax.inject.Named) LinkedList(java.util.LinkedList) Nullable(javax.annotation.Nullable) TaskDef(com.netflix.conductor.common.metadata.tasks.TaskDef) Logger(org.slf4j.Logger) WorkflowStatus(com.netflix.conductor.common.run.Workflow.WorkflowStatus) Predicate(java.util.function.Predicate) WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) Set(java.util.Set) Collectors(java.util.stream.Collectors) WorkflowTask(com.netflix.conductor.common.metadata.workflow.WorkflowTask) SCHEDULED(com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED) Monitors(com.netflix.conductor.metrics.Monitors) TERMINATE(com.netflix.conductor.common.metadata.workflow.TaskType.TERMINATE) List(java.util.List) TIMED_OUT(com.netflix.conductor.common.metadata.tasks.Task.Status.TIMED_OUT) Optional(java.util.Optional) TaskType(com.netflix.conductor.common.metadata.workflow.TaskType) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Configuration(com.netflix.conductor.core.config.Configuration) PayloadType(com.netflix.conductor.common.utils.ExternalPayloadStorage.PayloadType) Collections(java.util.Collections) Task(com.netflix.conductor.common.metadata.tasks.Task) WorkflowTask(com.netflix.conductor.common.metadata.workflow.WorkflowTask) WorkflowDef(com.netflix.conductor.common.metadata.workflow.WorkflowDef) WorkflowTask(com.netflix.conductor.common.metadata.workflow.WorkflowTask)

Aggregations

WorkflowDef (com.netflix.conductor.common.metadata.workflow.WorkflowDef)247 Test (org.junit.Test)185 WorkflowTask (com.netflix.conductor.common.metadata.workflow.WorkflowTask)173 Workflow (com.netflix.conductor.common.run.Workflow)128 HashMap (java.util.HashMap)123 Task (com.netflix.conductor.common.metadata.tasks.Task)100 TaskDef (com.netflix.conductor.common.metadata.tasks.TaskDef)71 SubWorkflow (com.netflix.conductor.core.execution.tasks.SubWorkflow)49 ArrayList (java.util.ArrayList)43 LinkedList (java.util.LinkedList)37 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)35 List (java.util.List)33 UserTask (com.netflix.conductor.tests.utils.UserTask)28 Map (java.util.Map)25 SubWorkflowParams (com.netflix.conductor.common.metadata.workflow.SubWorkflowParams)20 ConstraintViolation (javax.validation.ConstraintViolation)14 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)13 ApplicationException (com.netflix.conductor.core.execution.ApplicationException)13 ValidatorFactory (javax.validation.ValidatorFactory)13 DynamicForkJoinTaskList (com.netflix.conductor.common.metadata.workflow.DynamicForkJoinTaskList)12