use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo in project blueocean-plugin by jenkinsci.
the class PipelineNodeGraphVisitor method parallelStart.
@Override
public void parallelStart(@Nonnull FlowNode parallelStartNode, @Nonnull FlowNode branchNode, @Nonnull ForkScanner scanner) {
if (isNodeVisitorDumpEnabled) {
dump(String.format("parallelStart=> id: %s, name: %s, function: %s", parallelStartNode.getId(), parallelStartNode.getDisplayName(), parallelStartNode.getDisplayFunctionName()));
dump(String.format("\tbranch=> id: %s, name: %s, function: %s", branchNode.getId(), branchNode.getDisplayName(), branchNode.getDisplayFunctionName()));
}
if (nestedbranches.size() != parallelBranchEndNodes.size()) {
logger.error(String.format("nestedBranches size: %s not equal to parallelBranchEndNodes: %s", nestedbranches.size(), parallelBranchEndNodes.size()));
return;
}
while (!nestedbranches.empty() && !parallelBranchEndNodes.empty()) {
FlowNode branchStartNode = nestedbranches.pop();
FlowNode endNode = parallelBranchEndNodes.pop();
TimingInfo times;
NodeRunStatus status;
if (endNode != null) {
times = StatusAndTiming.computeChunkTiming(run, chunk.getPauseTimeMillis(), branchStartNode, endNode, chunk.getNodeAfter());
if (endNode instanceof StepAtomNode) {
if (PipelineNodeUtil.isPausedForInputStep((StepAtomNode) endNode, inputAction)) {
status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.PAUSED);
} else {
status = new NodeRunStatus(endNode);
}
} else {
GenericStatus genericStatus = StatusAndTiming.computeChunkStatus(run, parallelStartNode, branchStartNode, endNode, parallelEnd);
status = new NodeRunStatus(genericStatus);
}
} else {
times = new TimingInfo(TimingAction.getStartTime(branchStartNode) + System.currentTimeMillis(), chunk.getPauseTimeMillis(), TimingAction.getStartTime(branchStartNode));
status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.RUNNING);
}
FlowNodeWrapper branch = new FlowNodeWrapper(branchStartNode, status, times, run);
if (nextStage != null) {
branch.addEdge(nextStage.getId());
}
parallelBranches.push(branch);
}
FlowNodeWrapper[] sortedBranches = parallelBranches.toArray(new FlowNodeWrapper[parallelBranches.size()]);
Arrays.sort(sortedBranches, new Comparator<FlowNodeWrapper>() {
@Override
public int compare(FlowNodeWrapper o1, FlowNodeWrapper o2) {
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
});
parallelBranches.clear();
for (int i = 0; i < sortedBranches.length; i++) {
parallelBranches.push(sortedBranches[i]);
}
for (FlowNodeWrapper p : parallelBranches) {
nodes.push(p);
nodeMap.put(p.getId(), p);
}
//reset parallelEnd node for next parallel block
this.parallelEnd = null;
}
use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo in project blueocean-plugin by jenkinsci.
the class PipelineStepVisitor method handleChunkDone.
@Override
protected void handleChunkDone(@Nonnull MemoryFlowChunk chunk) {
if (stageStepsCollectionCompleted) {
//if its completed no further action
return;
}
if (node != null && chunk.getFirstNode().equals(node)) {
stageStepsCollectionCompleted = true;
inStageScope = false;
try {
final String cause = PipelineNodeUtil.getCauseOfBlockage(chunk.getFirstNode(), agentNode, run);
if (cause != null) {
//Now add a step that indicates bloackage cause
FlowNode step = new AtomNode(chunk.getFirstNode().getExecution(), UUID.randomUUID().toString(), chunk.getFirstNode()) {
@Override
protected String getTypeDisplayName() {
return cause;
}
};
FlowNodeWrapper stepNode = new FlowNodeWrapper(step, new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.QUEUED), new TimingInfo(), run);
steps.push(stepNode);
stepMap.put(step.getId(), stepNode);
}
} catch (IOException | InterruptedException e) {
//log the error but don't fail. This is better as in worst case all we will lose is blockage cause of a node.
logger.error(String.format("Error trying to get blockage status of pipeline: %s, runId: %s node block: %s. %s", run.getParent().getFullName(), run.getId(), agentNode, e.getMessage()), e);
}
}
if (node != null && PipelineNodeUtil.isStage(node) && !inStageScope && !chunk.getFirstNode().equals(node)) {
resetSteps();
}
}
use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo in project blueocean-plugin by jenkinsci.
the class PipelineStepVisitor method atomNode.
@Override
public void atomNode(@CheckForNull FlowNode before, @Nonnull FlowNode atomNode, @CheckForNull FlowNode after, @Nonnull ForkScanner scan) {
if (stageStepsCollectionCompleted && !PipelineNodeUtil.isSyntheticStage(currentStage)) {
return;
}
if (atomNode instanceof StepEndNode) {
this.closestEndNode = (StepEndNode) atomNode;
}
if (atomNode instanceof StepAtomNode && !PipelineNodeUtil.isSkippedStage(currentStage)) {
//if skipped stage, we don't collect its steps
long pause = PauseAction.getPauseDuration(atomNode);
chunk.setPauseTimeMillis(chunk.getPauseTimeMillis() + pause);
TimingInfo times = StatusAndTiming.computeChunkTiming(run, pause, atomNode, atomNode, after);
if (times == null) {
times = new TimingInfo();
}
NodeRunStatus status;
InputStep inputStep = null;
if (PipelineNodeUtil.isPausedForInputStep((StepAtomNode) atomNode, inputAction)) {
status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.PAUSED);
try {
for (InputStepExecution execution : inputAction.getExecutions()) {
FlowNode node = execution.getContext().get(FlowNode.class);
if (node != null && node.equals(atomNode)) {
inputStep = execution.getInput();
break;
}
}
} catch (IOException | InterruptedException | TimeoutException e) {
logger.error("Error getting FlowNode from execution context: " + e.getMessage(), e);
}
} else {
status = new NodeRunStatus(atomNode);
}
FlowNodeWrapper node = new FlowNodeWrapper(atomNode, status, times, inputStep, run);
if (PipelineNodeUtil.isPreSyntheticStage(currentStage)) {
preSteps.add(node);
} else if (PipelineNodeUtil.isPostSyntheticStage(currentStage)) {
postSteps.add(node);
} else {
if (!steps.contains(node)) {
steps.push(node);
}
}
stepMap.put(node.getId(), node);
//If there is closest block boundary, we capture it's error to the last step encountered and prepare for next block.
if (closestEndNode != null && closestEndNode.getError() != null) {
node.setBlockErrorAction(closestEndNode.getError());
//prepare for next block
closestEndNode = null;
}
}
}
use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo in project blueocean-plugin by jenkinsci.
the class PipelineNodeGraphVisitor method union.
@Override
public List<BluePipelineNode> union(List<FlowNodeWrapper> that, Link parent) {
List<FlowNodeWrapper> currentNodes = new ArrayList<>(nodes);
int currentNodeSize = nodes.size();
int futureNodeSize = that.size();
if (currentNodeSize < futureNodeSize) {
for (int i = currentNodeSize; i < futureNodeSize; i++) {
FlowNodeWrapper futureNode = that.get(i);
//stitch future nodes to last nodes of current incomplete heads
if (currentNodeSize > 0 && i == currentNodeSize) {
FlowNodeWrapper latestNode = currentNodes.get(i - 1);
if (latestNode.type == FlowNodeWrapper.NodeType.STAGE) {
if (futureNode.type == FlowNodeWrapper.NodeType.STAGE) {
latestNode.addEdge(futureNode.getId());
} else if (futureNode.type == FlowNodeWrapper.NodeType.PARALLEL) {
FlowNodeWrapper thatStage = futureNode.getFirstParent();
if (thatStage.equals(latestNode)) {
for (String edge : thatStage.edges) {
if (!latestNode.edges.contains(edge)) {
latestNode.addEdge(edge);
}
}
}
}
} else if (latestNode.type == FlowNodeWrapper.NodeType.PARALLEL) {
String futureNodeId = null;
FlowNodeWrapper thatStage = null;
if (futureNode.type == FlowNodeWrapper.NodeType.STAGE) {
thatStage = futureNode;
futureNodeId = futureNode.getId();
} else if (futureNode.type == FlowNodeWrapper.NodeType.PARALLEL && futureNode.getFirstParent().equals(latestNode.getFirstParent())) {
thatStage = futureNode.getFirstParent();
if (futureNode.edges.size() > 0) {
futureNodeId = futureNode.edges.get(0);
}
}
FlowNodeWrapper stage = latestNode.getFirstParent();
if (stage != null) {
//Add future node as edge to all edges of last stage
for (String id : stage.edges) {
FlowNodeWrapper node = nodeMap.get(id);
if (node != null && futureNodeId != null) {
node.addEdge(futureNodeId);
}
}
//now patch edges in case its partial
if (thatStage != null && futureNode.type == FlowNodeWrapper.NodeType.PARALLEL) {
for (String edge : thatStage.edges) {
if (!stage.edges.contains(edge)) {
stage.addEdge(edge);
}
}
}
}
}
}
FlowNodeWrapper n = new FlowNodeWrapper(futureNode.getNode(), new NodeRunStatus(null, null), new TimingInfo(), run);
n.addEdges(futureNode.edges);
n.addParents(futureNode.getParents());
currentNodes.add(n);
}
}
List<BluePipelineNode> newNodes = new ArrayList<>();
for (FlowNodeWrapper n : currentNodes) {
newNodes.add(new PipelineNodeImpl(n, parent, run));
}
return newNodes;
}
use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo in project blueocean-plugin by jenkinsci.
the class PipelineNodeGraphVisitor method handleChunkDone.
// This gets triggered on encountering a new chunk (stage or branch)
@Override
protected void handleChunkDone(@Nonnull MemoryFlowChunk chunk) {
if (isNodeVisitorDumpEnabled)
dump(String.format("handleChunkDone=> id: %s, name: %s, function: %s", chunk.getFirstNode().getId(), chunk.getFirstNode().getDisplayName(), chunk.getFirstNode().getDisplayFunctionName()));
if (PipelineNodeUtil.isSyntheticStage(chunk.getFirstNode())) {
return;
}
// its stage inside parallel, we skip it and clear nest stages collected inside parallel
if (parallelEnd != null) {
return;
}
if (!nestedStages.empty()) {
//we throw away nested stages
nestedStages.pop();
if (!nestedStages.empty()) {
//there is still a nested stage, return
return;
}
}
TimingInfo times = null;
//TODO: remove chunk.getLastNode() != null check based on how JENKINS-40200 gets resolved
if (firstExecuted != null && chunk.getLastNode() != null) {
times = StatusAndTiming.computeChunkTiming(run, chunk.getPauseTimeMillis(), firstExecuted, chunk.getLastNode(), chunk.getNodeAfter());
}
if (times == null) {
times = new TimingInfo();
}
NodeRunStatus status;
boolean skippedStage = PipelineNodeUtil.isSkippedStage(chunk.getFirstNode());
if (skippedStage) {
status = new NodeRunStatus(BlueRun.BlueRunResult.NOT_BUILT, BlueRun.BlueRunState.SKIPPED);
} else if (firstExecuted == null) {
status = new NodeRunStatus(GenericStatus.NOT_EXECUTED);
} else if (chunk.getLastNode() != null) {
status = new NodeRunStatus(StatusAndTiming.computeChunkStatus(run, chunk.getNodeBefore(), firstExecuted, chunk.getLastNode(), chunk.getNodeAfter()));
} else {
status = new NodeRunStatus(firstExecuted);
}
if (!pendingInputSteps.isEmpty()) {
status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.PAUSED);
}
FlowNodeWrapper stage = new FlowNodeWrapper(chunk.getFirstNode(), status, times, run);
try {
String cause = PipelineNodeUtil.getCauseOfBlockage(stage.getNode(), agentNode, run);
stage.setCauseOfFailure(cause);
} catch (IOException | InterruptedException e) {
//log the error but don't fail. This is better as in worst case all we will lose is blockage cause of a node.
logger.error(String.format("Error trying to get blockage status of pipeline: %s, runId: %s node block: %s. %s", run.getParent().getFullName(), run.getId(), agentNode, e.getMessage()), e);
}
nodes.push(stage);
nodeMap.put(stage.getId(), stage);
if (!skippedStage && !parallelBranches.isEmpty()) {
Iterator<FlowNodeWrapper> branches = parallelBranches.descendingIterator();
while (branches.hasNext()) {
FlowNodeWrapper p = branches.next();
p.addParent(stage);
stage.addEdge(p.getId());
}
} else {
if (nextStage != null) {
nextStage.addParent(stage);
stage.addEdge(nextStage.getId());
}
}
parallelBranches.clear();
this.nextStage = stage;
}
Aggregations