diff --git a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java index e04d6322..262c01a3 100644 --- a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java +++ b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java @@ -41,6 +41,7 @@ import org.jenkinsci.plugins.workflow.graph.StepNode; import org.jenkinsci.plugins.workflow.graphanalysis.LinearBlockHoppingScanner; import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.support.actions.PauseAction; import org.jenkinsci.plugins.workflow.support.concurrent.Timeout; import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution.PlaceholderTask; @@ -58,14 +59,17 @@ public class ThrottleQueueTaskDispatcher extends QueueTaskDispatcher { @Deprecated @Override public @CheckForNull CauseOfBlockage canTake(Node node, Task task) { + CauseOfBlockage cause = null; if (Jenkins.getAuthentication().equals(ACL.SYSTEM)) { - return canTakeImpl(node, task); - } - - // Throttle-concurrent-builds requires READ permissions for all projects. - try (ACLContext ctx = ACL.as(ACL.SYSTEM)) { - return canTakeImpl(node, task); + cause = canTakeImpl(node, task); + } else { + // Throttle-concurrent-builds requires READ permissions for all projects. + try (ACLContext ctx = ACL.as(ACL.SYSTEM)) { + cause = canTakeImpl(node, task); + } } + updatePauseAction(task, cause); + return cause; } private CauseOfBlockage canTakeImpl(Node node, Task task) { @@ -214,14 +218,17 @@ private boolean shouldBeThrottled(@NonNull Task task, @CheckForNull ThrottleJobP } private CauseOfBlockage canRun(Task task, ThrottleJobProperty tjp, List pipelineCategories) { + CauseOfBlockage cause = null; if (Jenkins.getAuthentication().equals(ACL.SYSTEM)) { - return canRunImpl(task, tjp, pipelineCategories); - } - + cause = canRunImpl(task, tjp, pipelineCategories); + } else { // Throttle-concurrent-builds requires READ permissions for all projects. - try (ACLContext ctx = ACL.as(ACL.SYSTEM)) { - return canRunImpl(task, tjp, pipelineCategories); + try (ACLContext ctx = ACL.as(ACL.SYSTEM)) { + cause = canRunImpl(task, tjp, pipelineCategories); + } } + updatePauseAction(task, cause); + return cause; } private CauseOfBlockage canRunImpl(Task task, ThrottleJobProperty tjp, List pipelineCategories) { @@ -682,5 +689,26 @@ private int getMaxConcurrentPerNodeBasedOnMatchingLabels( return maxConcurrentPerNodeLabeledIfMatch; } + private void updatePauseAction(Task task, CauseOfBlockage cause) { + if (task instanceof PlaceholderTask) { + PlaceholderTask placeholderTask = (PlaceholderTask)task; + try { + FlowNode flowNode = placeholderTask.getNode(); + if (cause != null) { + if (flowNode.getAction(PauseAction.class) == null) { + flowNode.addAction(new PauseAction(cause.getShortDescription())); + } + } else { + PauseAction.endCurrentPause(flowNode); + } + } catch (IOException|InterruptedException e) { + LOGGER.log( + Level.WARNING, + "Error setting pause action on pipeline {0}: {1}", + new Object[] {task.getDisplayName(), e}); + } + } + } + private static final Logger LOGGER = Logger.getLogger(ThrottleQueueTaskDispatcher.class.getName()); } diff --git a/src/test/java/hudson/plugins/throttleconcurrents/TestUtil.java b/src/test/java/hudson/plugins/throttleconcurrents/TestUtil.java index 08c37fb3..cf15b1bf 100644 --- a/src/test/java/hudson/plugins/throttleconcurrents/TestUtil.java +++ b/src/test/java/hudson/plugins/throttleconcurrents/TestUtil.java @@ -8,6 +8,7 @@ import hudson.model.Computer; import hudson.model.Executor; import hudson.model.Node; +import hudson.model.Queue; import hudson.model.queue.CauseOfBlockage; import hudson.slaves.DumbSlave; import hudson.slaves.RetentionStrategy; @@ -15,6 +16,7 @@ import jenkins.model.queue.CompositeCauseOfBlockage; import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.support.actions.PauseAction; import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution; import org.junit.rules.TemporaryFolder; import org.jvnet.hudson.test.JenkinsRule; @@ -106,6 +108,13 @@ static Set getBlockageReasons(CauseOfBlockage cob) { } } + static void hasPauseActionForItem(Queue.Item item) throws Exception { + assertTrue(item.task instanceof ExecutorStepExecution.PlaceholderTask); + ExecutorStepExecution.PlaceholderTask task = + (ExecutorStepExecution.PlaceholderTask)item.task; + assertNotNull(task.getNode().getAction(PauseAction.class)); + } + static void hasPlaceholderTaskForRun(Node n, WorkflowRun r) throws Exception { for (Executor exec : n.toComputer().getExecutors()) { if (exec.getCurrentExecutable() != null) { diff --git a/src/test/java/hudson/plugins/throttleconcurrents/ThrottleStepTest.java b/src/test/java/hudson/plugins/throttleconcurrents/ThrottleStepTest.java index c838e3a5..37f79874 100644 --- a/src/test/java/hudson/plugins/throttleconcurrents/ThrottleStepTest.java +++ b/src/test/java/hudson/plugins/throttleconcurrents/ThrottleStepTest.java @@ -98,6 +98,7 @@ public void onePerNode() throws Exception { assertThat( blockageReasons, hasItem(Messages._ThrottleQueueTaskDispatcher_MaxCapacityOnNode(1).toString())); + TestUtil.hasPauseActionForItem(queuedItem); assertEquals(1, agent.toComputer().countBusy()); TestUtil.hasPlaceholderTaskForRun(agent, firstJobFirstRun);