Search in sources :

Example 1 with FlowInterruptedException

use of org.jenkinsci.plugins.workflow.steps.FlowInterruptedException in project workflow-job-plugin by jenkinsci.

the class WorkflowRun method finish.

/**
 * Handles normal build completion (including errors) but also handles the case that the flow did not even start correctly, for example due to an error in {@link FlowExecution#start}.
 */
private void finish(@Nonnull Result r, @CheckForNull Throwable t) {
    setResult(r);
    duration = Math.max(0, System.currentTimeMillis() - getStartTimeInMillis());
    LOGGER.log(Level.INFO, "{0} completed: {1}", new Object[] { toString(), getResult() });
    if (listener == null) {
        LOGGER.log(Level.WARNING, this + " failed to start", t);
    } else {
        RunListener.fireCompleted(WorkflowRun.this, listener);
        if (t instanceof AbortException) {
            listener.error(t.getMessage());
        } else if (t instanceof FlowInterruptedException) {
            ((FlowInterruptedException) t).handle(this, listener);
        } else if (t != null) {
            // TODO 2.43+ use Functions.printStackTrace
            listener.getLogger().println(Functions.printThrowable(t).trim());
        }
        listener.finished(getResult());
        listener.closeQuietly();
    }
    logsToCopy = null;
    try {
        save();
    } catch (Exception x) {
        LOGGER.log(Level.WARNING, "failed to save " + this, x);
    }
    Timer.get().submit(() -> {
        try {
            getParent().logRotate();
        } catch (Exception x) {
            LOGGER.log(Level.WARNING, "failed to perform log rotation after " + this, x);
        }
    });
    onEndBuilding();
    if (completed != null) {
        synchronized (completed) {
            completed.set(true);
        }
    }
    FlowExecutionList.get().unregister(new Owner(this));
    try {
        StashManager.maybeClearAll(this);
    } catch (IOException x) {
        LOGGER.log(Level.WARNING, "failed to clean up stashes from " + this, x);
    }
    FlowExecution exec = getExecution();
    if (exec != null) {
        FlowExecutionListener.fireCompleted(exec);
    }
}
Also used : FlowExecutionOwner(org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner) FlowExecution(org.jenkinsci.plugins.workflow.flow.FlowExecution) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) IOException(java.io.IOException) AbortException(hudson.AbortException) IOException(java.io.IOException) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) AbortException(hudson.AbortException)

Example 2 with FlowInterruptedException

use of org.jenkinsci.plugins.workflow.steps.FlowInterruptedException in project workflow-cps-plugin by jenkinsci.

the class CpsFlowExecution method interrupt.

@Override
public void interrupt(Result result, CauseOfInterruption... causes) throws IOException, InterruptedException {
    setResult(result);
    LOGGER.log(Level.FINE, "Interrupting {0} as {1}", new Object[] { owner, result });
    final FlowInterruptedException ex = new FlowInterruptedException(result, causes);
    // stop all ongoing activities
    runInCpsVmThread(new FutureCallback<CpsThreadGroup>() {

        @Override
        public void onSuccess(CpsThreadGroup g) {
            // don't touch outer ones. See JENKINS-26148
            Map<FlowHead, CpsThread> m = new LinkedHashMap<>();
            for (CpsThread t : g.threads.values()) {
                m.put(t.head, t);
            }
            // for each inner most CpsThread, from young to old...
            for (CpsThread t : Iterators.reverse(ImmutableList.copyOf(m.values()))) {
                try {
                    t.stop(ex);
                } catch (Exception x) {
                    LOGGER.log(Level.WARNING, "Failed to abort " + owner, x);
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOGGER.log(Level.WARNING, "Failed to interrupt steps in " + owner, t);
        }
    });
    // If we are still rehydrating pickles, try to stop that now.
    Collection<ListenableFuture<?>> futures = pickleFutures;
    if (futures != null) {
        LOGGER.log(Level.FINE, "We are still rehydrating pickles in {0}", owner);
        for (ListenableFuture<?> future : futures) {
            if (!future.isDone()) {
                LOGGER.log(Level.FINE, "Trying to cancel {0} for {1}", new Object[] { future, owner });
                if (!future.cancel(true)) {
                    LOGGER.log(Level.WARNING, "Failed to cancel {0} for {1}", new Object[] { future, owner });
                }
            }
        }
    }
}
Also used : ListenableFuture(com.google.common.util.concurrent.ListenableFuture) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) TreeMap(java.util.TreeMap) ImmutableMap(com.google.common.collect.ImmutableMap) NavigableMap(java.util.NavigableMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) UsernameNotFoundException(org.acegisecurity.userdetails.UsernameNotFoundException) AbortException(hudson.AbortException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException)

Example 3 with FlowInterruptedException

use of org.jenkinsci.plugins.workflow.steps.FlowInterruptedException in project workflow-cps-plugin by jenkinsci.

the class CpsStepContext method completed.

private void completed(@Nonnull Outcome newOutcome) {
    if (outcome == null) {
        outcome = newOutcome;
        scheduleNextRun();
        whenOutcomeDelivered = new Throwable();
    } else {
        Throwable failure = newOutcome.getAbnormal();
        if (failure instanceof FlowInterruptedException) {
            for (CauseOfInterruption cause : ((FlowInterruptedException) failure).getCauses()) {
                if (cause instanceof BodyFailed) {
                    LOGGER.log(Level.FINE, "already completed " + this + " and now received body failure", failure);
                    // Predictable that the error would be thrown up here; quietly ignore it.
                    return;
                }
            }
        }
        LOGGER.log(Level.WARNING, "already completed " + this, new IllegalStateException("delivered here"));
        if (failure != null) {
            LOGGER.log(Level.INFO, "new failure", failure);
        } else {
            LOGGER.log(Level.INFO, "new success: {0}", outcome.getNormal());
        }
        if (whenOutcomeDelivered != null) {
            LOGGER.log(Level.INFO, "previously delivered here", whenOutcomeDelivered);
        }
        failure = outcome.getAbnormal();
        if (failure != null) {
            LOGGER.log(Level.INFO, "earlier failure", failure);
        } else {
            LOGGER.log(Level.INFO, "earlier success: {0}", outcome.getNormal());
        }
    }
}
Also used : CauseOfInterruption(jenkins.model.CauseOfInterruption) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException)

Example 4 with FlowInterruptedException

use of org.jenkinsci.plugins.workflow.steps.FlowInterruptedException in project workflow-cps-plugin by jenkinsci.

the class CpsStepContext method scheduleNextRun.

/**
 * When this step context has completed execution (successful or otherwise), plan the next action.
 */
private void scheduleNextRun() {
    if (syncMode) {
        // plan the next action.
        return;
    }
    try {
        final FlowNode n = getNode();
        final CpsFlowExecution flow = getFlowExecution();
        final List<FlowNode> parents = new ArrayList<FlowNode>();
        for (int head : bodyHeads) {
            FlowHead flowHead = flow.getFlowHead(head);
            if (flowHead != null) {
                parents.add(flowHead.get());
            } else {
                LOGGER.log(Level.WARNING, "Could not find flow head #{0}", head);
            }
        }
        flow.runInCpsVmThread(new FutureCallback<CpsThreadGroup>() {

            @CpsVmThreadOnly
            @Override
            public void onSuccess(CpsThreadGroup g) {
                g.unexport(body);
                body = null;
                CpsThread thread = getThread(g);
                if (thread != null) {
                    CpsThread nit = thread.getNextInner();
                    if (nit != null) {
                        // can't mark this done until the inner thread is done.
                        // defer the processing until the inner thread is done
                        nit.addCompletionHandler(new ScheduleNextRun());
                        if (getOutcome().isFailure()) {
                            // if the step with a currently running body reported a failure,
                            // make some effort to try to interrupt the running body
                            StepExecution s = nit.getStep();
                            if (s != null) {
                                // TODO: ideally this needs to work like interrupt, in that
                                // if s==null the next StepExecution gets interrupted when it happen
                                FlowInterruptedException cause = new FlowInterruptedException(Result.FAILURE, new BodyFailed());
                                cause.initCause(getOutcome().getAbnormal());
                                try {
                                    // TODO JENKINS-26148/JENKINS-34637 this is probably wrong: should interrupt the innermost execution
                                    // (the “next” one could be block-scoped, and we would want to interrupt all parallel heads)
                                    s.stop(cause);
                                } catch (Exception e) {
                                    LOGGER.log(Level.WARNING, "Failed to stop the body execution in response to the failure of the parent");
                                }
                            }
                        }
                        return;
                    }
                    if (n instanceof StepStartNode) {
                        // if there's no body to invoke, we want the current thread to be the sole head
                        if (parents.isEmpty())
                            parents.add(thread.head.get());
                        // clear all the subsumed heads that are joining. thread that owns parents.get(0) lives on
                        for (int i = 1; i < parents.size(); i++) g.getExecution().subsumeHead(parents.get(i));
                        StepEndNode en = new StepEndNode(flow, (StepStartNode) n, parents);
                        thread.head.setNewHead(en);
                        CpsFlowExecution.maybeAutoPersistNode(en);
                    }
                    thread.head.markIfFail(getOutcome());
                    thread.setStep(null);
                    thread.resume(getOutcome());
                }
            }

            /**
             * Program state failed to load.
             */
            @Override
            public void onFailure(Throwable t) {
            }
        });
    } catch (IOException x) {
        LOGGER.log(Level.FINE, null, x);
    }
}
Also used : StepStartNode(org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode) ArrayList(java.util.ArrayList) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) StepEndNode(org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode) IOException(java.io.IOException) StepExecution(org.jenkinsci.plugins.workflow.steps.StepExecution) InvokerInvocationException(org.codehaus.groovy.runtime.InvokerInvocationException) IOException(java.io.IOException) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) ExecutionException(java.util.concurrent.ExecutionException) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode)

Example 5 with FlowInterruptedException

use of org.jenkinsci.plugins.workflow.steps.FlowInterruptedException in project workflow-cps-plugin by jenkinsci.

the class CpsThreadGroup method run.

/**
 * Run the CPS program a little bit.
 *
 * <p>
 * The amount of execution needs to be small enough so as not to hog CPS VM thread
 * In particular, time sensitive activities like the interruption wants to run on CPS VM thread.
 *
 * @return
 *      true if this program can still execute further. false if the program is suspended
 *      and requires some external event to become resumable again. The false return value
 *      is akin to a Unix thread waiting for I/O completion.
 */
@CpsVmThreadOnly("root")
private boolean run() {
    boolean changed = false;
    boolean ending = false;
    boolean stillRunnable = false;
    // TODO: maybe instead of running all the thread, run just one thread in round robin
    for (CpsThread t : threads.values().toArray(new CpsThread[threads.size()])) {
        if (t.isRunnable()) {
            Outcome o = t.runNextChunk();
            if (o.isFailure()) {
                // failed thread is non-resumable
                assert !t.isAlive();
                // workflow produced an exception
                Result result = Result.FAILURE;
                Throwable error = o.getAbnormal();
                if (error instanceof FlowInterruptedException) {
                    result = ((FlowInterruptedException) error).getResult();
                }
                execution.setResult(result);
                FlowNode fn = t.head.get();
                if (fn != null) {
                    t.head.get().addAction(new ErrorAction(error));
                }
            }
            if (!t.isAlive()) {
                LOGGER.fine("completed " + t);
                // do this after ErrorAction is set above
                t.fireCompletionHandlers(o);
                threads.remove(t.id);
                if (threads.isEmpty()) {
                    execution.onProgramEnd(o);
                    ending = true;
                }
            } else {
                stillRunnable |= t.isRunnable();
            }
            changed = true;
        }
    }
    if (changed && !stillRunnable) {
        execution.persistedClean = null;
        saveProgramIfPossible(false);
    }
    if (ending) {
        execution.cleanUpHeap();
        if (scripts != null) {
            scripts.clear();
        }
        closures.clear();
        try {
            Util.deleteFile(execution.getProgramDataFile());
        } catch (IOException x) {
            LOGGER.log(Level.WARNING, "Failed to delete program.dat in " + execution, x);
        }
    }
    return stillRunnable;
}
Also used : ErrorAction(org.jenkinsci.plugins.workflow.actions.ErrorAction) Outcome(com.cloudbees.groovy.cps.Outcome) FlowInterruptedException(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) IOException(java.io.IOException) Result(hudson.model.Result) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode)

Aggregations

FlowInterruptedException (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException)7 IOException (java.io.IOException)4 FlowNode (org.jenkinsci.plugins.workflow.graph.FlowNode)3 AbortException (hudson.AbortException)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 ExecutionException (java.util.concurrent.ExecutionException)2 Outcome (com.cloudbees.groovy.cps.Outcome)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)1 Result (hudson.model.Result)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 NavigableMap (java.util.NavigableMap)1 TreeMap (java.util.TreeMap)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1 TimeoutException (java.util.concurrent.TimeoutException)1 CauseOfInterruption (jenkins.model.CauseOfInterruption)1 UsernameNotFoundException (org.acegisecurity.userdetails.UsernameNotFoundException)1 InvokerInvocationException (org.codehaus.groovy.runtime.InvokerInvocationException)1