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);
}
}
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 });
}
}
}
}
}
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());
}
}
}
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);
}
}
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;
}
Aggregations