Skip to content

Commit

Permalink
[JENKINS-11997] Consider jobs in the Executors for priority sorter
Browse files Browse the repository at this point in the history
Introducing "Run Exclusive", with "Run Exclusive" set on a 
JobGroup only Jobs from that JobGroup will be started
until no more Jobs from that JobGroup is in queue being run.
  • Loading branch information
emsa23 committed Dec 9, 2013
1 parent c6fa0cb commit fe2e1d1
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
10 changes: 10 additions & 0 deletions src/main/java/jenkins/advancedqueue/JobGroup.java
Expand Up @@ -78,6 +78,7 @@ public void setPriorityStrategy(PriorityStrategy priorityStrategy) {
private int id = 0;
private int priority = 2;
private String view;
private boolean runExclusive = false;
private boolean useJobFilter = false;
private String jobPattern = ".*";
private boolean usePriorityStrategies;
Expand Down Expand Up @@ -128,6 +129,14 @@ public void setView(String view) {
this.view = view;
}

public boolean isRunExclusive() {
return runExclusive;
}

public void setRunExclusive(boolean runExclusive) {
this.runExclusive = runExclusive;
}

/**
* @return the useJobFilter
*/
Expand Down Expand Up @@ -185,6 +194,7 @@ public static JobGroup newInstance(StaplerRequest req, JSONObject jobGroupObject
jobGroup.setId(id);
jobGroup.setPriority(jobGroupObject.getInt("priority"));
jobGroup.setView(jobGroupObject.getString("view"));
jobGroup.setRunExclusive(Boolean.parseBoolean(jobGroupObject.getString("runExclusive")));
jobGroup.setUseJobFilter(jobGroupObject.has("useJobFilter"));
if (jobGroup.isUseJobFilter()) {
JSONObject jsonObject = jobGroupObject.getJSONObject("useJobFilter");
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/jenkins/advancedqueue/PriorityConfiguration.java
Expand Up @@ -27,7 +27,6 @@
import hudson.ExtensionList;
import hudson.matrix.MatrixConfiguration;
import hudson.matrix.MatrixProject;
import hudson.model.AbstractProject;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Job;
Expand All @@ -42,8 +41,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
Expand Down Expand Up @@ -71,6 +72,7 @@ public class PriorityConfiguration extends Descriptor<PriorityConfiguration> imp

private final static Logger LOGGER = Logger.getLogger(PriorityConfiguration.class.getName());

transient private Map<Integer, JobGroup> id2jobGroup;
private List<JobGroup> jobGroups;

public PriorityConfiguration() {
Expand All @@ -84,13 +86,14 @@ public int compare(JobGroup o1, JobGroup o2) {
}
});
//
id2jobGroup = new HashMap<Integer, JobGroup>();
for (JobGroup jobGroup : jobGroups) {
id2jobGroup.put(jobGroup.getId(), jobGroup);
Collections.sort(jobGroup.getPriorityStrategies(), new Comparator<JobGroup.PriorityStrategyHolder>() {
public int compare(JobGroup.PriorityStrategyHolder o1, JobGroup.PriorityStrategyHolder o2) {
return o1.getId() - o2.getId();
}
});

}
}

Expand Down Expand Up @@ -125,6 +128,10 @@ public ListBoxModel getListViewItems() {
}
return items;
}

public JobGroup getJobGroup(int id) {
return id2jobGroup.get(id);
}

public ExtensionList<Descriptor<PriorityStrategy>> getPriorityStrategyDescriptors() {
return PriorityStrategy.all();
Expand All @@ -137,6 +144,7 @@ public ListBoxModel getPriorities() {

public void doPriorityConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
jobGroups = new LinkedList<JobGroup>();
id2jobGroup = new HashMap<Integer, JobGroup>();
//
String parameter = req.getParameter("json");
JSONObject jobGroupsObject = JSONObject.fromObject(parameter);
Expand All @@ -149,6 +157,7 @@ public void doPriorityConfigSubmit(StaplerRequest req, StaplerResponse rsp) thro
}
JobGroup jobGroup = JobGroup.newInstance(req, jobGroupObject, id++);
jobGroups.add(jobGroup);
id2jobGroup.put(jobGroup.getId(), jobGroup);
}
save();
rsp.sendRedirect(Jenkins.getInstance().getRootUrl());
Expand Down Expand Up @@ -177,8 +186,10 @@ public PriorityConfigurationCallback getPriority(Queue.Item item, PriorityConfig
if (job instanceof MatrixConfiguration) {
MatrixProject matrixProject = ((MatrixConfiguration) job).getParent();
ItemInfo itemInfo = QueueItemCache.get().getItem(matrixProject.getName());
System.out.println(matrixProject.getName() + " - " + itemInfo);
// Can be null (for example) at startup when the MatrixBuild got lost (was running at restart)
if(itemInfo != null) {
System.out.println(itemInfo.getPriority() + "/" + itemInfo.getJobGroupId());
return priorityCallback.setPrioritySelection(itemInfo.getPriority(), itemInfo.getJobGroupId());
}
return priorityCallback.setPrioritySelection(PrioritySorterConfiguration.get().getStrategy().getDefaultPriority());
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/jenkins/advancedqueue/RunExclusiveThrottler.java
@@ -0,0 +1,77 @@
package jenkins.advancedqueue;

import hudson.Extension;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.Queue.Item;
import hudson.model.Queue.LeftItem;
import hudson.model.listeners.RunListener;
import hudson.model.queue.CauseOfBlockage;
import hudson.model.queue.QueueTaskDispatcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jenkins.advancedqueue.sorter.ItemInfo;
import jenkins.advancedqueue.sorter.QueueItemCache;
import jenkins.model.Jenkins;

public class RunExclusiveThrottler {

static private List<String> exclusiveJobs = Collections.synchronizedList(new ArrayList<String>());
static private int exclusiveJobGroupId = -1;
static private String exclusiveJobName = "";

@Extension
static public class RunExclusiveRunListener extends RunListener<Run> {

@Override
public void onStarted(Run r, TaskListener listener) {
System.out.println("Started: " + r.getParent().getName());
ItemInfo item = QueueItemCache.get().getItem(r.getParent().getName());
if (PriorityConfiguration.get().getJobGroup(item.getJobGroupId()).isRunExclusive()) {
System.out.println("Is Exclusive");
exclusiveJobGroupId = item.getJobGroupId();
exclusiveJobName = item.getJobName();
exclusiveJobs.add(item.getJobName());
}
}

@Override
public void onCompleted(Run r, TaskListener listener) {
exclusiveJobs.remove(r.getParent().getName());
}

}

private static class RunExclusiveMode extends CauseOfBlockage {

@Override
public String getShortDescription() {
return "Run Exclusive (" + exclusiveJobName + ")";
}

}

@Extension
static public class RunExclusiveDispatcher extends QueueTaskDispatcher {

@Override
public CauseOfBlockage canRun(Item item) {
if(exclusiveJobs.size() > 0) {
System.out.println(QueueItemCache.get().getItem(item.id).getJobGroupId() + " = " + exclusiveJobGroupId);
if (QueueItemCache.get().getItem(item.id).getJobGroupId() != exclusiveJobGroupId) {
System.out.println("dENY " + item.task.getName());
return new RunExclusiveMode();
}
}
System.out.println("Allow " + item.task.getName());
return null;
}

}

}
Expand Up @@ -41,12 +41,15 @@
</j:forEach>
</select>
</f:entry>
<f:entry title="Run Exclusive (experimental)">
<f:checkbox name="runExclusive" value="${jobGroup.runExclusive}" checked="${jobGroup.runExclusive}"/>
</f:entry>
<f:optionalBlock name="useJobFilter" checked="${jobGroup.useJobFilter}" title="Use a regular expression to only include a subset of the jobs in the view">
<f:entry title="Regular Expression">
<f:textbox name="jobPattern" value="${jobGroup.jobPattern}" checkUrl="'${rootURL}/descriptorByName/jenkins.advancedqueue.PriorityConfiguration/checkJobPattern?value='+encode(this.value)"/>
</f:entry>
</f:optionalBlock>
<f:optionalBlock name="usePriorityStrategies" checked="${jobGroup.usePriorityStrategies}" title="Use additional rules when assigning a priority to a Job">
<f:optionalBlock name="usePriorityStrategies" checked="${jobGroup.usePriorityStrategies}" title="Use additional rules when assigning a priority to a Job">
<f:entry>
<f:repeatable var="holder" items="${jobGroup.priorityStrategies}" header="Priority Strategy">
<table width="75%">
Expand Down

0 comments on commit fe2e1d1

Please sign in to comment.