public void determineExecutionPlan() { List<TaskInfo> nodeQueue = CollectionUtils.collect( new ArrayList<Task>(entryTasks), new Transformer<TaskInfo, Task>() { public TaskInfo transform(Task original) { return graph.getNode(original); } }); Set<TaskInfo> visitingNodes = new HashSet<TaskInfo>(); while (!nodeQueue.isEmpty()) { TaskInfo taskNode = nodeQueue.get(0); boolean filtered = !filter.isSatisfiedBy(taskNode.getTask()); if (filtered) { taskNode.setRequired(false); } if (!taskNode.getRequired() || executionPlan.containsKey(taskNode.getTask())) { nodeQueue.remove(0); continue; } if (visitingNodes.add(taskNode)) { // Have not seen this task before - add its dependencies to the head of the queue and leave // this // task in the queue ArrayList<TaskInfo> dependsOnTasks = new ArrayList<TaskInfo>(); addAllReversed(dependsOnTasks, taskNode.getHardSuccessors()); addAllReversed(dependsOnTasks, taskNode.getSoftSuccessors()); for (TaskInfo dependsOnTask : dependsOnTasks) { if (visitingNodes.contains(dependsOnTask)) { throw new CircularReferenceException( String.format( "Circular dependency between tasks. Cycle includes [%s, %s].", taskNode.getTask(), dependsOnTask.getTask())); } nodeQueue.add(0, dependsOnTask); } } else { // Have visited this task's dependencies - add it to the end of the plan nodeQueue.remove(0); visitingNodes.remove(taskNode); executionPlan.put(taskNode.getTask(), taskNode); } } }
public TaskInfo getTaskToExecute() { lock.lock(); try { while (true) { TaskInfo nextMatching = null; boolean allTasksComplete = true; for (TaskInfo taskInfo : executionPlan.values()) { allTasksComplete = allTasksComplete && taskInfo.isComplete(); if (taskInfo.isReady() && taskInfo.allDependenciesComplete() && !runningProjects.contains(taskInfo.getTask().getProject().getPath())) { nextMatching = taskInfo; break; } } if (allTasksComplete) { return null; } if (nextMatching == null) { try { condition.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } } else { if (nextMatching.allDependenciesSuccessful()) { nextMatching.startExecution(); runningProjects.add(nextMatching.getTask().getProject().getPath()); return nextMatching; } else { nextMatching.skipExecution(); condition.signalAll(); } } } } finally { lock.unlock(); } }
public void taskComplete(TaskInfo taskInfo) { lock.lock(); try { if (taskInfo.isFailed()) { handleFailure(taskInfo); } taskInfo.finishExecution(); runningProjects.remove(taskInfo.getTask().getProject().getPath()); condition.signalAll(); } finally { lock.unlock(); } }
private void handleFailure(TaskInfo taskInfo) { Throwable executionFailure = taskInfo.getExecutionFailure(); if (executionFailure != null) { // Always abort execution for an execution failure (as opposed to a task failure) abortExecution(); this.failures.add(executionFailure); return; } // Task failure try { failureHandler.onTaskFailure(taskInfo.getTask()); this.failures.add(taskInfo.getTaskFailure()); } catch (Exception e) { // If the failure handler rethrows exception, then execution of other tasks is aborted. // (--continue will collect failures) abortExecution(); this.failures.add(e); } }