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);
}
}
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;
}
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());
}
}
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);
}
}
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);
}
Aggregations