use of hudson.model.Hudson in project hudson-2.x by hudson.
the class NodeProvisioner method update.
/**
* Periodically invoked to keep track of the load.
* Launches additional nodes if necessary.
*/
private void update() {
Hudson hudson = Hudson.getInstance();
// clean up the cancelled launch activity, then count the # of executors that we are about to bring up.
float plannedCapacity = 0;
for (Iterator<PlannedNode> itr = pendingLaunches.iterator(); itr.hasNext(); ) {
PlannedNode f = itr.next();
if (f.future.isDone()) {
try {
hudson.addNode(f.future.get());
LOGGER.info(f.displayName + " provisioning successfully completed. We have now " + hudson.getComputers().length + " computer(s)");
} catch (InterruptedException e) {
// since we confirmed that the future is already done
throw new AssertionError(e);
} catch (ExecutionException e) {
LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", e.getCause());
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", e);
}
itr.remove();
} else
plannedCapacity += f.numExecutors;
}
plannedCapacitiesEMA.update(plannedCapacity);
/*
Here we determine how many additional slaves we need to keep up with the load (if at all),
which involves a simple math.
Broadly speaking, first we check that all the executors are fully utilized before attempting
to start any new slave (this also helps to ignore the temporary gap between different numbers,
as changes in them are not necessarily synchronized --- for example, there's a time lag between
when a slave launches (thus bringing the planned capacity down) and the time when its executors
pick up builds (thus bringing the queue length down.)
Once we confirm that, we compare the # of buildable items against the additional slaves
that are being brought online. If we have more jobs than our executors can handle, we'll launch a new slave.
So this computation involves three stats:
1. # of idle executors
2. # of jobs that are starving for executors
3. # of additional slaves being provisioned (planned capacities.)
To ignore a temporary surge/drop, we make conservative estimates on each one of them. That is,
we take the current snapshot value, and we take the current exponential moving average (EMA) value,
and use the max/min.
This is another measure to be robust against temporary surge/drop in those indicators, and helps
us avoid over-reacting to stats.
If we only use the snapshot value or EMA value, tests confirmed that the gap creates phantom
excessive loads and Hudson ends up firing excessive capacities. In a static system, over the time
EMA and the snapshot value becomes the same, so this makes sure that in a long run this conservative
estimate won't create a starvation.
*/
int idleSnapshot = stat.computeIdleExecutors();
int totalSnapshot = stat.computeTotalExecutors();
float idle = Math.max(stat.getLatestIdleExecutors(TIME_SCALE), idleSnapshot);
if (idle < MARGIN) {
// make sure the system is fully utilized before attempting any new launch.
// this is the amount of work left to be done
float qlen = Math.min(stat.queueLength.getLatest(TIME_SCALE), stat.computeQueueLength());
// ... and this is the additional executors we've already provisioned.
plannedCapacity = Math.max(plannedCapacitiesEMA.getLatest(TIME_SCALE), plannedCapacity);
float excessWorkload = qlen - plannedCapacity;
float m = calcThresholdMargin(totalSnapshot);
if (excessWorkload > 1 - m) {
// and there's more work to do...
LOGGER.fine("Excess workload " + excessWorkload + " detected. (planned capacity=" + plannedCapacity + ",Qlen=" + qlen + ",idle=" + idle + "&" + idleSnapshot + ",total=" + totalSnapshot + "m,=" + m + ")");
for (Cloud c : hudson.clouds) {
// enough slaves allocated
if (excessWorkload < 0)
break;
// provisioning a new node should be conservative --- for example if exceeWorkload is 1.4,
// we don't want to allocate two nodes but just one.
// OTOH, because of the exponential decay, even when we need one slave, excess workload is always
// something like 0.95, in which case we want to allocate one node.
// so the threshold here is 1-MARGIN, and hence floor(excessWorkload+MARGIN) is needed to handle this.
Collection<PlannedNode> additionalCapacities = c.provision(label, (int) Math.round(Math.floor(excessWorkload + m)));
for (PlannedNode ac : additionalCapacities) {
excessWorkload -= ac.numExecutors;
LOGGER.info("Started provisioning " + ac.displayName + " from " + c.name + " with " + ac.numExecutors + " executors. Remaining excess workload:" + excessWorkload);
}
pendingLaunches.addAll(additionalCapacities);
}
}
}
}
use of hudson.model.Hudson in project hudson-2.x by hudson.
the class HudsonFilter method init.
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
// this is how we make us available to the rest of Hudson.
filterConfig.getServletContext().setAttribute(HudsonFilter.class.getName(), this);
try {
Hudson hudson = Hudson.getInstance();
if (hudson != null) {
// looks like we are initialized after Hudson came into being. initialize it now. See #3069
LOGGER.fine("Security wasn't initialized; Initializing it...");
SecurityRealm securityRealm = hudson.getSecurityRealm();
reset(securityRealm);
LOGGER.fine("securityRealm is " + securityRealm);
LOGGER.fine("Security initialized");
}
} catch (ExceptionInInitializerError e) {
// see HUDSON-4592. In some containers this happens before
// WebAppMain.contextInitialized kicks in, which makes
// the whole thing fail hard before a nicer error check
// in WebAppMain.contextInitialized. So for now,
// just report it here, and let the WebAppMain handle the failure gracefully.
LOGGER.log(SEVERE, "Failed to initialize Hudson", e);
}
}
use of hudson.model.Hudson in project hudson-2.x by hudson.
the class DoubleLaunchChecker method getId.
/**
* Figures out a string that identifies this instance of Hudson.
*/
public String getId() {
Hudson h = Hudson.getInstance();
// in servlet 2.5, we can get the context path
String contextPath = "";
try {
Method m = ServletContext.class.getMethod("getContextPath");
contextPath = " contextPath=\"" + m.invoke(h.servletContext) + "\"";
} catch (Exception e) {
// maybe running with Servlet 2.4
}
return h.hashCode() + contextPath + " at " + ManagementFactory.getRuntimeMXBean().getName();
}
use of hudson.model.Hudson in project hudson-2.x by hudson.
the class NodeServiceImplTest method setUp.
@Before
public void setUp() throws Exception {
// static methods
mockStatic(Hudson.class);
// final and native
hudson = mock(Hudson.class);
MockitoAnnotations.initMocks(this);
nodeService = new NodeServiceImpl(security);
nodeService.setHudson(hudson);
}
use of hudson.model.Hudson in project hudson-2.x by hudson.
the class ProjectServiceImplTest method setUp.
@Before
public void setUp() throws Exception {
mockStatic(Hudson.class);
hudson = PowerMockito.mock(Hudson.class);
PowerMockito.mockStatic(JobUuid.class);
MockitoAnnotations.initMocks(this);
this.projectService = new ProjectServiceImpl(securityService);
this.projectService.setHudson(hudson);
assertThat(getInst(), notNullValue());
}
Aggregations