-
Notifications
You must be signed in to change notification settings - Fork 116
Add PauseAction when throttling pipelines #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
||
|
|
@@ -54,14 +55,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) { | ||
|
|
@@ -218,14 +222,17 @@ private boolean shouldBeThrottled(@NonNull Task task, @CheckForNull ThrottleJobP | |
| } | ||
|
|
||
| private CauseOfBlockage canRun(Task task, ThrottleJobProperty tjp, List<String> pipelineCategories) { | ||
| CauseOfBlockage cause = null; | ||
| if (Jenkins.getAuthentication().equals(ACL.SYSTEM)) { | ||
| return canRunImpl(task, tjp, pipelineCategories); | ||
| } | ||
|
|
||
| // Throttle-concurrent-builds requires READ permissions for all projects. | ||
| try (ACLContext ctx = ACL.as(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)) { | ||
| cause = canRunImpl(task, tjp, pipelineCategories); | ||
| } | ||
| } | ||
| updatePauseAction(task, cause); | ||
| return cause; | ||
| } | ||
|
|
||
| private CauseOfBlockage canRunImpl(Task task, ThrottleJobProperty tjp, List<String> pipelineCategories) { | ||
|
|
@@ -695,5 +702,31 @@ private int getMaxConcurrentPerNodeBasedOnMatchingLabels( | |
| return maxConcurrentPerNodeLabeledIfMatch; | ||
| } | ||
|
|
||
| private void updatePauseAction(Task task, CauseOfBlockage cause) { | ||
| if (task instanceof PlaceholderTask) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, see above. |
||
| PlaceholderTask placeholderTask = (PlaceholderTask) task; | ||
| try { | ||
| FlowNode flowNode = placeholderTask.getNode(); | ||
nickb-carallon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (flowNode == null) { | ||
| return; | ||
| } | ||
|
|
||
| if (cause != null) { | ||
| if (PauseAction.getCurrentPause(flowNode) == null) { | ||
| flowNode.addAction(new PauseAction(cause.getShortDescription())); | ||
| } | ||
| } else { | ||
| if (PauseAction.getCurrentPause(flowNode) != null) { | ||
| 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()); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,6 +95,7 @@ public void onePerNode() throws Exception { | |
| blockageReasons, | ||
| hasItem(Messages._ThrottleQueueTaskDispatcher_MaxCapacityOnNode(1) | ||
| .toString())); | ||
| TestUtil.hasPauseActionForItem(queuedItem); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This assertion needs to be added to other tests as well, at least in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| assertEquals(1, agent.toComputer().countBusy()); | ||
| TestUtil.hasPlaceholderTaskForRun(agent, firstJobFirstRun); | ||
|
|
||
|
|
@@ -176,6 +177,8 @@ public void multipleCategories() throws Exception { | |
| WorkflowRun thirdJobFirstRun = thirdJob.scheduleBuild2(0).waitForStart(); | ||
| j.waitForMessage("Still waiting to schedule task", thirdJobFirstRun); | ||
| assertFalse(j.jenkins.getQueue().isEmpty()); | ||
| Queue.Item queuedItem = j.jenkins.getQueue().getItems()[0]; | ||
| TestUtil.hasPauseActionForItem(queuedItem); | ||
| assertEquals(1, firstAgent.toComputer().countBusy()); | ||
| TestUtil.hasPlaceholderTaskForRun(firstAgent, firstJobFirstRun); | ||
|
|
||
|
|
@@ -245,6 +248,9 @@ public void onePerNodeParallel() throws Exception { | |
| j.waitForMessage("Still waiting to schedule task", run1); | ||
| j.waitForMessage("Still waiting to schedule task", run2); | ||
|
|
||
| Queue.Item queuedItem = j.jenkins.getQueue().getItems()[0]; | ||
| TestUtil.hasPauseActionForItem(queuedItem); | ||
|
|
||
| SemaphoreStep.success("wait-first-branch-a-job/1", null); | ||
| SemaphoreStep.waitForStart("wait-first-branch-c-job/1", run1); | ||
| assertEquals(1, firstAgent.toComputer().countBusy()); | ||
|
|
@@ -293,6 +299,8 @@ public void twoTotal() throws Exception { | |
| j.waitForMessage("Still waiting to schedule task", thirdJobFirstRun); | ||
| j.jenkins.getQueue().maintain(); | ||
| assertFalse(j.jenkins.getQueue().isEmpty()); | ||
| Queue.Item queuedItem = j.jenkins.getQueue().getItems()[0]; | ||
| TestUtil.hasPauseActionForItem(queuedItem); | ||
| assertEquals(1, firstAgent.toComputer().countBusy()); | ||
| TestUtil.hasPlaceholderTaskForRun(firstAgent, firstJobFirstRun); | ||
|
|
||
|
|
@@ -377,6 +385,8 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen | |
| WorkflowRun secondJobFirstRun = secondJob.scheduleBuild2(0).waitForStart(); | ||
| j.waitForMessage("Still waiting to schedule task", secondJobFirstRun); | ||
| assertFalse(j.jenkins.getQueue().isEmpty()); | ||
| Queue.Item queuedItem = j.jenkins.getQueue().getItems()[0]; | ||
| TestUtil.hasPauseActionForItem(queuedItem); | ||
|
|
||
| assertEquals(1, agent.toComputer().countBusy()); | ||
| for (Executor e : agent.toComputer().getExecutors()) { | ||
|
|
@@ -460,6 +470,7 @@ private String getThrottleScript(String jobName, List<String> categories, String | |
| return "throttle([" | ||
| + StringUtils.join(quoted, ", ") | ||
| + "]) {\n" | ||
| + "stage('wait') {\n" | ||
| + " echo 'hi there'\n" | ||
| + " node('" | ||
| + label | ||
|
|
@@ -468,6 +479,7 @@ private String getThrottleScript(String jobName, List<String> categories, String | |
| + jobName | ||
| + "-job'\n" | ||
| + " }\n" | ||
| + "}\n" | ||
| + "}\n"; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this relate to throttling of Pipeline jobs with a throttle job property rather than a
throttlestep? Every other usage ofnew PauseActionthat I can find in thejenkinsciorganization (e.g. in Lockable Resource, SonarQube, and Pipeline: Input Step) is from aStepExecution. Should this be specific to athrottlestep (seeThrottleStepandThrottleStepExecution)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pause action only applies to stages within a pipeline, so doesn't apply for pipelines using the throttle job property.