Skip to content

Commit 769bb74

Browse files
jglickdwnusbaum
andauthored
[JENKINS-50407] Better diagnosis for certain fatal loading errors (#809)
* [JENKINS-50407] Better diagnosis for certain fatal loading errors * Abandon elaborate logic in `loadProgramFailed` * `Supplier`-based overload Co-authored-by: Devin Nusbaum <[email protected]> --------- Co-authored-by: Devin Nusbaum <[email protected]>
1 parent 5d695de commit 769bb74

File tree

2 files changed

+31
-43
lines changed

2 files changed

+31
-43
lines changed

plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
import com.cloudbees.groovy.cps.Env;
2929
import com.cloudbees.groovy.cps.Envs;
3030
import com.cloudbees.groovy.cps.Outcome;
31-
import com.cloudbees.groovy.cps.impl.ConstantBlock;
32-
import com.cloudbees.groovy.cps.impl.ThrowBlock;
3331
import com.cloudbees.groovy.cps.sandbox.Invoker;
3432
import com.cloudbees.jenkins.support.api.Component;
3533
import com.cloudbees.jenkins.support.api.Container;
@@ -107,6 +105,7 @@
107105
import hudson.AbortException;
108106
import hudson.BulkChange;
109107
import hudson.Extension;
108+
import hudson.Functions;
110109
import hudson.init.Terminator;
111110
import hudson.model.Item;
112111
import hudson.model.Job;
@@ -840,51 +839,17 @@ public void onFailure(Throwable t) {
840839
}
841840

842841
/**
843-
* Used by {@link #loadProgramAsync(File)} to propagate a failure to load the persisted execution state.
844-
* <p>
845-
* Let the workflow interrupt by throwing an exception that indicates how it failed.
842+
* Used to propagate a failure to load the persisted execution state.
846843
* @param promise same as {@link #programPromise} but more strongly typed
847844
*/
848845
private void loadProgramFailed(final Throwable problem, SettableFuture<CpsThreadGroup> promise) {
849-
FlowHead head;
850-
851-
synchronized(this) {
852-
if (heads == null || heads.isEmpty()) {
853-
head = null;
854-
} else {
855-
head = getFirstHead();
856-
}
857-
}
858-
859-
if (head==null) {
860-
// something went catastrophically wrong and there's no live head. fake one
861-
head = new FlowHead(this);
862-
try {
863-
head.newStartNode(new FlowStartNode(this, iotaStr()));
864-
} catch (IOException e) {
865-
LOGGER.log(Level.FINE, "Failed to persist", e);
866-
}
846+
try {
847+
Functions.printStackTrace(problem, owner.getListener().getLogger());
848+
} catch (Exception x) {
849+
LOGGER.log(Level.WARNING, x, () -> "failed to log problem to " + owner);
867850
}
868-
869-
870-
CpsThreadGroup g = new CpsThreadGroup(this);
871-
final FlowHead head_ = head;
872-
873-
promise.set(g);
874-
runInCpsVmThread(new FutureCallback<>() {
875-
@Override public void onSuccess(CpsThreadGroup g) {
876-
CpsThread t = g.addThread(
877-
new Continuable(new ThrowBlock(new ConstantBlock(
878-
problem instanceof AbortException || problem instanceof FlowInterruptedException ? problem : new IOException("Failed to load build state", problem)))),
879-
head_, null
880-
);
881-
t.resume(new Outcome(null,null));
882-
}
883-
@Override public void onFailure(Throwable t) {
884-
LOGGER.log(Level.WARNING, "Failed to set program failure on " + owner, t);
885-
croak(t);
886-
}
887-
});
851+
promise.setException(problem);
852+
croak(new AbortException("Failed to load program"));
888853
}
889854

890855
/** Report a fatal error in the VM. */

plugin/src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,29 @@ private void trustedShell(final boolean pos) throws Throwable {
608608
});
609609
}
610610

611+
@Issue("JENKINS-50407")
612+
@Test public void shellLoadingError() throws Throwable {
613+
sessions.then(r -> {
614+
WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p");
615+
p.setDefinition(new CpsFlowDefinition("semaphore 'wait'", true));
616+
SemaphoreStep.waitForStart("wait/1", p.scheduleBuild2(0).waitForStart());
617+
});
618+
sessions.then(r -> {
619+
r.assertLogContains("IllegalStateException: decorator problem here",
620+
r.assertBuildStatus(Result.FAILURE,
621+
r.waitForCompletion(r.jenkins.getItemByFullName("p", WorkflowJob.class).getLastBuild())));
622+
});
623+
}
624+
@TestExtension("shellLoadingError") public static final class BrokenDecorator extends GroovyShellDecorator {
625+
static int count;
626+
@Override
627+
public void configureShell(CpsFlowExecution context, GroovyShell shell) {
628+
if (count++ == 1) {
629+
throw new IllegalStateException("decorator problem here");
630+
}
631+
}
632+
}
633+
611634
/**
612635
* This field shouldn't be visible to regular script.
613636
*/

0 commit comments

Comments
 (0)