in core/src/main/java/hudson/slaves/RetentionStrategy.java [217:276]
public long check(final SlaveComputer c) {
if (c.isOffline() && c.isLaunchSupported()) {
final HashMap<Computer, Integer> availableComputers = new HashMap<>();
for (Computer o : Jenkins.get().getComputers()) {
if ((o.isOnline() || o.isConnecting()) && o.isPartiallyIdle() && o.isAcceptingTasks()) {
final int idleExecutors = o.countIdle();
if (idleExecutors>0)
availableComputers.put(o, idleExecutors);
}
}
boolean needComputer = false;
long demandMilliseconds = 0;
for (Queue.BuildableItem item : Queue.getInstance().getBuildableItems()) {
// can any of the currently idle executors take this task?
// assume the answer is no until we can find such an executor
boolean needExecutor = true;
for (Computer o : Collections.unmodifiableSet(availableComputers.keySet())) {
Node otherNode = o.getNode();
if (otherNode != null && otherNode.canTake(item) == null) {
needExecutor = false;
final int availableExecutors = availableComputers.remove(o);
if (availableExecutors > 1) {
availableComputers.put(o, availableExecutors - 1);
} else {
availableComputers.remove(o);
}
break;
}
}
// this 'item' cannot be built by any of the existing idle nodes, but it can be built by 'c'
Node checkedNode = c.getNode();
if (needExecutor && checkedNode != null && checkedNode.canTake(item) == null) {
demandMilliseconds = System.currentTimeMillis() - item.buildableStartMilliseconds;
needComputer = demandMilliseconds > TimeUnit.MINUTES.toMillis(inDemandDelay);
break;
}
}
if (needComputer) {
// we've been in demand for long enough
logger.log(Level.INFO, "Launching computer {0} as it has been in demand for {1}",
new Object[]{c.getName(), Util.getTimeSpanString(demandMilliseconds)});
c.connect(false);
}
} else if (c.isIdle()) {
final long idleMilliseconds = System.currentTimeMillis() - c.getIdleStartMilliseconds();
if (idleMilliseconds > TimeUnit.MINUTES.toMillis(idleDelay)) {
// we've been idle for long enough
logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle for {1}",
new Object[]{c.getName(), Util.getTimeSpanString(idleMilliseconds)});
c.disconnect(new OfflineCause.IdleOfflineCause());
} else {
// no point revisiting until we can be confident we will be idle
return TimeUnit.MILLISECONDS.toMinutes(TimeUnit.MINUTES.toMillis(idleDelay) - idleMilliseconds);
}
}
return 1;
}