use of com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED in project conductor by Netflix.
the class WorkflowExecutor method resetCallbacksForWorkflow.
/**
* @param workflowId the id of the workflow for which task callbacks are to be reset
* @throws ApplicationException if the workflow is in terminal state
*/
public void resetCallbacksForWorkflow(String workflowId) {
Workflow workflow = executionDAOFacade.getWorkflowById(workflowId, true);
if (workflow.getStatus().isTerminal()) {
throw new ApplicationException(CONFLICT, "Workflow is in terminal state. Status =" + workflow.getStatus());
}
// Get SIMPLE tasks in SCHEDULED state that have callbackAfterSeconds > 0 and set the callbackAfterSeconds to 0
workflow.getTasks().stream().filter(task -> !isSystemTask.test(task) && SCHEDULED.equals(task.getStatus()) && task.getCallbackAfterSeconds() > 0).forEach(task -> {
if (queueDAO.resetOffsetTime(QueueUtils.getQueueName(task), task.getTaskId())) {
task.setCallbackAfterSeconds(0);
executionDAOFacade.updateTask(task);
}
});
}
use of com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED in project conductor by Netflix.
the class DeciderService method decide.
private DeciderOutcome decide(final Workflow workflow, List<Task> preScheduledTasks) throws TerminateWorkflowException {
DeciderOutcome outcome = new DeciderOutcome();
if (workflow.getStatus().isTerminal()) {
// you cannot evaluate a terminal workflow
LOGGER.debug("Workflow {} is already finished. Reason: {}", workflow, workflow.getReasonForIncompletion());
return outcome;
}
checkWorkflowTimeout(workflow);
if (workflow.getStatus().equals(WorkflowStatus.PAUSED)) {
LOGGER.debug("Workflow " + workflow.getWorkflowId() + " is paused");
return outcome;
}
// Filter the list of tasks and include only tasks that are not retried, not executed
// marked to be skipped and not part of System tasks that is DECISION, FORK, JOIN
// This list will be empty for a new workflow being started
List<Task> pendingTasks = workflow.getTasks().stream().filter(isNonPendingTask).collect(Collectors.toList());
// Get all the tasks that have not completed their lifecycle yet
// This list will be empty for a new workflow
Set<String> executedTaskRefNames = workflow.getTasks().stream().filter(Task::isExecuted).map(Task::getReferenceTaskName).collect(Collectors.toSet());
Map<String, Task> tasksToBeScheduled = new LinkedHashMap<>();
preScheduledTasks.forEach(preScheduledTask -> {
tasksToBeScheduled.put(preScheduledTask.getReferenceTaskName(), preScheduledTask);
});
// A new workflow does not enter this code branch
for (Task pendingTask : pendingTasks) {
if (SystemTaskType.is(pendingTask.getTaskType()) && !pendingTask.getStatus().isTerminal()) {
tasksToBeScheduled.putIfAbsent(pendingTask.getReferenceTaskName(), pendingTask);
executedTaskRefNames.remove(pendingTask.getReferenceTaskName());
}
Optional<TaskDef> taskDefinition = pendingTask.getTaskDefinition();
if (!taskDefinition.isPresent()) {
taskDefinition = Optional.ofNullable(workflow.getWorkflowDefinition().getTaskByRefName(pendingTask.getReferenceTaskName())).map(WorkflowTask::getTaskDefinition);
}
if (taskDefinition.isPresent()) {
checkTaskTimeout(taskDefinition.get(), pendingTask);
checkTaskPollTimeout(taskDefinition.get(), pendingTask);
// If the task has not been updated for "responseTimeoutSeconds" then mark task as TIMED_OUT
if (isResponseTimedOut(taskDefinition.get(), pendingTask)) {
timeoutTask(taskDefinition.get(), pendingTask);
}
}
if (!pendingTask.getStatus().isSuccessful()) {
WorkflowTask workflowTask = pendingTask.getWorkflowTask();
if (workflowTask == null) {
workflowTask = workflow.getWorkflowDefinition().getTaskByRefName(pendingTask.getReferenceTaskName());
}
Optional<Task> retryTask = retry(taskDefinition.orElse(null), workflowTask, pendingTask, workflow);
if (retryTask.isPresent()) {
tasksToBeScheduled.put(retryTask.get().getReferenceTaskName(), retryTask.get());
executedTaskRefNames.remove(retryTask.get().getReferenceTaskName());
outcome.tasksToBeUpdated.add(pendingTask);
} else {
pendingTask.setStatus(COMPLETED_WITH_ERRORS);
}
}
if (!pendingTask.isExecuted() && !pendingTask.isRetried() && pendingTask.getStatus().isTerminal()) {
pendingTask.setExecuted(true);
List<Task> nextTasks = getNextTask(workflow, pendingTask);
if (pendingTask.isLoopOverTask() && !TaskType.DO_WHILE.name().equals(pendingTask.getTaskType()) && !nextTasks.isEmpty()) {
nextTasks = filterNextLoopOverTasks(nextTasks, pendingTask, workflow);
}
nextTasks.forEach(nextTask -> tasksToBeScheduled.putIfAbsent(nextTask.getReferenceTaskName(), nextTask));
outcome.tasksToBeUpdated.add(pendingTask);
LOGGER.debug("Scheduling Tasks from {}, next = {} for workflowId: {}", pendingTask.getTaskDefName(), nextTasks.stream().map(Task::getTaskDefName).collect(Collectors.toList()), workflow.getWorkflowId());
}
}
// All the tasks that need to scheduled are added to the outcome, in case of
List<Task> unScheduledTasks = tasksToBeScheduled.values().stream().filter(task -> !executedTaskRefNames.contains(task.getReferenceTaskName())).collect(Collectors.toList());
if (!unScheduledTasks.isEmpty()) {
LOGGER.debug("Scheduling Tasks: {} for workflow: {}", unScheduledTasks.stream().map(Task::getTaskDefName).collect(Collectors.toList()), workflow.getWorkflowId());
outcome.tasksToBeScheduled.addAll(unScheduledTasks);
}
if (containsSuccessfulTerminateTask.test(workflow) || (outcome.tasksToBeScheduled.isEmpty() && checkForWorkflowCompletion(workflow))) {
LOGGER.debug("Marking workflow: {} as complete.", workflow);
outcome.isComplete = true;
}
return outcome;
}
use of com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED in project conductor by Netflix.
the class DeciderService method getTasksToBeScheduled.
public List<Task> getTasksToBeScheduled(Workflow workflow, WorkflowTask taskToSchedule, int retryCount, String retriedTaskId) {
workflow = populateWorkflowAndTaskData(workflow);
Map<String, Object> input = parametersUtils.getTaskInput(taskToSchedule.getInputParameters(), workflow, null, null);
TaskType taskType = TaskType.USER_DEFINED;
String type = taskToSchedule.getType();
if (TaskType.isSystemTask(type)) {
taskType = TaskType.valueOf(type);
}
// get tasks already scheduled (in progress/terminal) for this workflow instance
List<String> tasksInWorkflow = workflow.getTasks().stream().filter(runningTask -> runningTask.getStatus().equals(Status.IN_PROGRESS) || runningTask.getStatus().isTerminal()).map(Task::getReferenceTaskName).collect(Collectors.toList());
String taskId = IDGenerator.generate();
TaskMapperContext taskMapperContext = TaskMapperContext.newBuilder().withWorkflowDefinition(workflow.getWorkflowDefinition()).withWorkflowInstance(workflow).withTaskDefinition(taskToSchedule.getTaskDefinition()).withTaskToSchedule(taskToSchedule).withTaskInput(input).withRetryCount(retryCount).withRetryTaskId(retriedTaskId).withTaskId(taskId).withDeciderService(this).build();
// for static forks, each branch of the fork creates a join task upon completion
// for dynamic forks, a join task is created with the fork and also with each branch of the fork
// a new task must only be scheduled if a task with the same reference name is not already in this workflow instance
List<Task> tasks = taskMappers.get(taskType.name()).getMappedTasks(taskMapperContext).stream().filter(task -> !tasksInWorkflow.contains(task.getReferenceTaskName())).collect(Collectors.toList());
tasks.forEach(this::externalizeTaskData);
return tasks;
}
use of com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED 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);
}
use of com.netflix.conductor.common.metadata.tasks.Task.Status.SCHEDULED in project conductor by Netflix.
the class AbstractWorkflowServiceTest method testSimpleWorkflowWithResponseTimeout.
@Test
public void testSimpleWorkflowWithResponseTimeout() throws Exception {
createWFWithResponseTimeout();
String correlationId = "unit_test_1";
Map<String, Object> workflowInput = new HashMap<>();
String inputParam1 = "p1 value";
workflowInput.put("param1", inputParam1);
workflowInput.put("param2", "p2 value");
String workflowId = startOrLoadWorkflowExecution("RTOWF", 1, correlationId, workflowInput, null, null);
logger.debug("testSimpleWorkflowWithResponseTimeout.wfid=" + workflowId);
assertNotNull(workflowId);
Workflow workflow = workflowExecutionService.getExecutionStatus(workflowId, true);
assertNotNull(workflow);
assertEquals(RUNNING, workflow.getStatus());
// The very first task is the one that should be scheduled.
assertEquals(1, workflow.getTasks().size());
assertEquals(1, queueDAO.getSize("task_rt"));
// Polling for the first task should return the first task
Task task = workflowExecutionService.poll("task_rt", "task1.junit.worker.testTimeout");
assertNotNull(task);
assertEquals("task_rt", task.getTaskType());
assertTrue(workflowExecutionService.ackTaskReceived(task.getTaskId()));
assertEquals(workflowId, task.getWorkflowInstanceId());
// As the task_rt is out of the queue, the next poll should not get it
Task nullTask = workflowExecutionService.poll("task_rt", "task1.junit.worker.testTimeout");
assertNull(nullTask);
Thread.sleep(10000);
workflowExecutor.decide(workflowId);
assertEquals(1, queueDAO.getSize("task_rt"));
// The first task would be timed_out and a new task will be scheduled
workflow = workflowExecutionService.getExecutionStatus(workflowId, true);
assertNotNull(workflow);
assertEquals(RUNNING, workflow.getStatus());
assertEquals(2, workflow.getTasks().size());
assertTrue(workflow.getTasks().stream().allMatch(t -> t.getReferenceTaskName().equals("task_rt_t1")));
assertEquals(TIMED_OUT, workflow.getTasks().get(0).getStatus());
assertEquals(SCHEDULED, workflow.getTasks().get(1).getStatus());
// Polling now should get the same task back because it should have been put back in the queue
Task taskAgain = workflowExecutionService.poll("task_rt", "task1.junit.worker");
assertNotNull(taskAgain);
// update task with callback after seconds greater than the response timeout
taskAgain.setStatus(IN_PROGRESS);
taskAgain.setCallbackAfterSeconds(2);
workflowExecutionService.updateTask(taskAgain);
workflow = workflowExecutionService.getExecutionStatus(workflowId, true);
assertNotNull(workflow);
assertEquals(WorkflowStatus.RUNNING, workflow.getStatus());
assertEquals(2, workflow.getTasks().size());
assertEquals(SCHEDULED, workflow.getTasks().get(1).getStatus());
// wait for callback after seconds which is longer than response timeout seconds and then call decide
Thread.sleep(2010);
// Ensure unacks are processed.
queueDAO.processUnacks(taskAgain.getTaskDefName());
workflowExecutor.decide(workflowId);
workflow = workflowExecutionService.getExecutionStatus(workflowId, true);
assertNotNull(workflow);
// Poll for task again
taskAgain = workflowExecutionService.poll("task_rt", "task1.junit.worker");
assertNotNull(taskAgain);
taskAgain.getOutputData().put("op", "task1.Done");
taskAgain.setStatus(COMPLETED);
workflowExecutionService.updateTask(taskAgain);
// poll for next task
task = workflowExecutionService.poll("junit_task_2", "task2.junit.worker.testTimeout");
assertNotNull(task);
assertEquals("junit_task_2", task.getTaskType());
assertTrue(workflowExecutionService.ackTaskReceived(task.getTaskId()));
task.setStatus(COMPLETED);
task.setReasonForIncompletion("unit test failure");
workflowExecutionService.updateTask(task);
workflow = workflowExecutionService.getExecutionStatus(workflowId, true);
assertNotNull(workflow);
assertEquals(WorkflowStatus.COMPLETED, workflow.getStatus());
}
Aggregations