Search in sources :

Example 1 with TimingInfo

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;
}
Also used : GenericStatus(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.GenericStatus) TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) StepAtomNode(org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode)

Example 2 with TimingInfo

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();
    }
}
Also used : TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) IOException(java.io.IOException) AtomNode(org.jenkinsci.plugins.workflow.graph.AtomNode) StepAtomNode(org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode)

Example 3 with TimingInfo

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;
        }
    }
}
Also used : TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) StepEndNode(org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode) IOException(java.io.IOException) StepAtomNode(org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode) InputStepExecution(org.jenkinsci.plugins.workflow.support.steps.input.InputStepExecution) InputStep(org.jenkinsci.plugins.workflow.support.steps.input.InputStep) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode) TimeoutException(java.util.concurrent.TimeoutException)

Example 4 with TimingInfo

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;
}
Also used : TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) ArrayList(java.util.ArrayList) BluePipelineNode(io.jenkins.blueocean.rest.model.BluePipelineNode)

Example 5 with TimingInfo

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;
}
Also used : TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) IOException(java.io.IOException)

Aggregations

TimingInfo (org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo)6 FlowNode (org.jenkinsci.plugins.workflow.graph.FlowNode)4 IOException (java.io.IOException)3 StepAtomNode (org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode)3 BluePipelineNode (io.jenkins.blueocean.rest.model.BluePipelineNode)1 BlueRun (io.jenkins.blueocean.rest.model.BlueRun)1 ArrayList (java.util.ArrayList)1 TimeoutException (java.util.concurrent.TimeoutException)1 Nullable (javax.annotation.Nullable)1 LabelAction (org.jenkinsci.plugins.workflow.actions.LabelAction)1 TimingAction (org.jenkinsci.plugins.workflow.actions.TimingAction)1 StepEndNode (org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode)1 AtomNode (org.jenkinsci.plugins.workflow.graph.AtomNode)1 GenericStatus (org.jenkinsci.plugins.workflow.pipelinegraphanalysis.GenericStatus)1 InputStep (org.jenkinsci.plugins.workflow.support.steps.input.InputStep)1 InputStepExecution (org.jenkinsci.plugins.workflow.support.steps.input.InputStepExecution)1