diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index 8211b7dbb..d03c463d2 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -1320,6 +1320,17 @@ public void onSuccess(CpsThreadGroup g) { LOGGER.log(Level.WARNING, "Failed to abort " + owner, x); } } + // The interruption above is only delivered into the CPS threads; propagating it (running catch and + // finally blocks, and ultimately ending the program) requires the CPS VM to run the program again, + // which CpsThreadGroup.scheduleRun refuses to do while paused. So drop the pause. + if (g.isPaused()) { + try { + owner.getListener().getLogger().println("Resuming to process abort"); + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, x); + } + g.unpause(); + } } @Override diff --git a/plugin/src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java b/plugin/src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java index 62ce9984d..6769e0259 100644 --- a/plugin/src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java +++ b/plugin/src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecutionTest.java @@ -336,6 +336,24 @@ public void pause() throws Throwable { }); } + @Test + public void abortWhilePaused() throws Throwable { + sessions.then(r -> { + WorkflowJob p = r.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition("try {semaphore 'wait'} finally {echo 'cleaning up'}", true)); + WorkflowRun b = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait/1", b); + CpsFlowExecution e = (CpsFlowExecution) b.getExecution(); + e.pause(true); + await().atMost(30, TimeUnit.SECONDS).until(e::isPaused); + b.getExecutor().interrupt(); + await().atMost(60, TimeUnit.SECONDS).until(() -> !b.isBuilding()); + r.assertBuildStatus(Result.ABORTED, b); + assertFalse(e.isPaused()); + r.assertLogContains("cleaning up", b); + }); + } + @Issue("JENKINS-32015") @Test public void quietDown() throws Throwable {