diff --git a/core/src/main/java/hudson/slaves/ComputerRetentionWork.java b/core/src/main/java/hudson/slaves/ComputerRetentionWork.java index 5a7f7249f70c35a8fe2c2961f36db399bda7b4c2..cf728476b0fa71d1b1f8dcf1e9fa3408a49da68d 100644 --- a/core/src/main/java/hudson/slaves/ComputerRetentionWork.java +++ b/core/src/main/java/hudson/slaves/ComputerRetentionWork.java @@ -20,13 +20,13 @@ public class ComputerRetentionWork extends SafeTimerTask { private final Map nextCheck = new WeakHashMap(); protected void doRun() { + final long startRun = System.currentTimeMillis(); for (Computer c : Hudson.getInstance().getComputers()) { - if (!nextCheck.containsKey(c) || System.currentTimeMillis() > nextCheck.get(c)) { + if (!nextCheck.containsKey(c) || startRun > nextCheck.get(c)) { // at the moment I don't trust strategies to wait more than 60 minutes // strategies need to wait at least one minute final long waitInMins = Math.min(1, Math.max(60, c.getRetentionStrategy().check(c))); - nextCheck.put(c, System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(waitInMins, TimeUnit.MINUTES)); + nextCheck.put(c, startRun + TimeUnit.MILLISECONDS.convert(waitInMins, TimeUnit.MINUTES)); } } } diff --git a/core/src/main/java/hudson/slaves/RetentionStrategy.java b/core/src/main/java/hudson/slaves/RetentionStrategy.java index 5a5bdcc078803a02f2af0379878d74e8da2304d8..e68d4f4c685b57cb5db506168e5d952caadcf773 100644 --- a/core/src/main/java/hudson/slaves/RetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/RetentionStrategy.java @@ -6,6 +6,8 @@ import hudson.util.DescriptorList; import org.kohsuke.stapler.DataBoundConstructor; import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import java.util.logging.Level; /** * Controls when to take {@link Computer} offline, bring it back online, or even to destroy it. @@ -102,6 +104,9 @@ public abstract class RetentionStrategy implements Describab * {@link hudson.slaves.RetentionStrategy} that tries to keep the node offline when not in use. */ public static class Demand extends RetentionStrategy { + + private static final Logger logger = Logger.getLogger(Demand.class.getName()); + /** * The delay (in minutes) for which the slave must be in demand before tring to launch it. */ @@ -113,7 +118,7 @@ public abstract class RetentionStrategy implements Describab private final long idleDelay; private transient Long finishTransition = null; - private transient Boolean finishState = null; + private transient Boolean startState = null; @DataBoundConstructor public Demand(long inDemandDelay, long idleDelay) { @@ -145,38 +150,47 @@ public abstract class RetentionStrategy implements Describab * {@inheritDoc} */ public synchronized long check(SlaveComputer c) { - if (Boolean.valueOf(c.isOffline()).equals(finishState)) { - // reset the timer as we are in the target state! + if (!Boolean.valueOf(c.isOffline()).equals(startState)) { + // reset the timer as we are no longer in the starting state finishTransition = null; - finishState = !c.isOffline(); + startState = c.isOffline(); } if (c.isOffline()) { final Queue queue = Hudson.getInstance().getQueue(); - if (queue.getItems().length == 0) { - // reset our timer - finishTransition = null; - } else { - if (finishTransition == null) { - // only just noticed we're in demand - finishTransition = System.currentTimeMillis() + - TimeUnit.MILLISECONDS.convert(inDemandDelay, TimeUnit.MINUTES); - } else if (System.currentTimeMillis() > finishTransition) { + final Queue.Item[] items = queue.getItems(); // TODO filter this array to this computer + for (Queue.Item item : items) { + if ((System.currentTimeMillis() - item.timestamp.getTimeInMillis()) > + TimeUnit.MILLISECONDS.convert(inDemandDelay, TimeUnit.MINUTES)) { + + logger.log(Level.INFO, "Trying to launch computer {0} as it has been in demand for too long", c.getNode().getNodeName()); // we've been in demand for long enough if (c.isOffline() && c.isLaunchSupported()) c.tryReconnect(); finishTransition = null; + + break; } } } else { if (c.isIdle()) { if (finishTransition == null) { + logger.log(Level.INFO, "Computer {0} is now idle, {1} minutes until disconnection", + new Object[]{c.getNode().getNodeName(), idleDelay}); // only just noticed that we're idle finishTransition = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(idleDelay, TimeUnit.MINUTES); } else if (System.currentTimeMillis() > finishTransition) { + logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle too long", c.getNode().getNodeName()); // we've been idle for long enough c.disconnect(); finishTransition = null; + } else { + logger.log(Level.INFO, "Computer {0} is still idle, {1} minutes until disconnection", + new Object[]{c.getNode().getNodeName(), + TimeUnit.MILLISECONDS.convert( + Math.max(0, finishTransition - System.currentTimeMillis()), + TimeUnit.MINUTES) + }); } } else { // reset our timer diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index a0d7bc47d6525194fd85b622671004c26a080272..ec077cbaba31c44fbcb635cca4fe9a4f27b503cb 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -217,7 +217,7 @@ public abstract class Trigger implements Describable> // clean up fingerprint once a day timer.scheduleAtFixedRate(new FingerprintCleanupThread(),DAY,DAY); timer.scheduleAtFixedRate(new WorkspaceCleanupThread(),DAY+4*HOUR,DAY); - timer.scheduleAtFixedRate(new ComputerRetentionWork(),15*MIN,1*MIN); + timer.scheduleAtFixedRate(new ComputerRetentionWork(), MIN, MIN); // start monitoring nodes, although there's no hurry. timer.schedule(new SafeTimerTask() {