diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 05ec1925a2de409792ba7c4bcda929b115960739..e3c95d7a380518395c1c860bb438c0121b53b114 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -269,6 +269,17 @@ public abstract class Computer extends AbstractModelObject { return true; } + /** + * Returns the time when this computer first became idle. + */ + public final long getIdleStartMilliseconds() { + long firstIdle = Long.MIN_VALUE; + for (Executor e : executors) { + firstIdle = Math.max(firstIdle, e.getIdleStartMilliseconds()); + } + return firstIdle; + } + /** * Called by {@link Executor} to kill excessive executors from this computer. */ diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index 2b295587c33e00b76ffd7e78e66d3a43ac329379..57939aea23735952341841533269f9a22d1e6774 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -22,6 +22,10 @@ public class Executor extends Thread implements ModelObject { private final Queue queue; private long startTime; + /** + * Used to track when a job was last executed. + */ + private long finishTime; /** * Executor number that identifies it among other executors for the same {@link Computer}. @@ -47,6 +51,7 @@ public class Executor extends Thread implements ModelObject { SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); try { + finishTime = System.currentTimeMillis(); while(true) { if(Hudson.getInstance().isTerminating()) return; @@ -81,6 +86,7 @@ public class Executor extends Thread implements ModelObject { // so just leave some info and go on to build other things LOGGER.log(Level.SEVERE, "Executor throw an exception unexpectedly",e); } + finishTime = System.currentTimeMillis(); executable = null; } } catch(RuntimeException e) { @@ -195,6 +201,18 @@ public class Executor extends Thread implements ModelObject { return owner; } + /** + * Returns when this executor started or should start being idle. + */ + public long getIdleStartMilliseconds() { + if (isIdle()) + return finishTime; + else { + return Math.max(startTime + executable.getParent().getEstimatedDuration(), + System.currentTimeMillis() + 15000); + } + } + /** * Returns the executor of the current thread. */ diff --git a/core/src/main/java/hudson/slaves/RetentionStrategy.java b/core/src/main/java/hudson/slaves/RetentionStrategy.java index e68d4f4c685b57cb5db506168e5d952caadcf773..ee6cf75da1b73768db3617efaa7576325da90cd5 100644 --- a/core/src/main/java/hudson/slaves/RetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/RetentionStrategy.java @@ -117,9 +117,6 @@ public abstract class RetentionStrategy implements Describab */ private final long idleDelay; - private transient Long finishTransition = null; - private transient Boolean startState = null; - @DataBoundConstructor public Demand(long inDemandDelay, long idleDelay) { this.inDemandDelay = inDemandDelay; @@ -150,55 +147,31 @@ public abstract class RetentionStrategy implements Describab * {@inheritDoc} */ public synchronized long check(SlaveComputer c) { - if (!Boolean.valueOf(c.isOffline()).equals(startState)) { - // reset the timer as we are no longer in the starting state - finishTransition = null; - startState = c.isOffline(); - } if (c.isOffline()) { final Queue queue = Hudson.getInstance().getQueue(); 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 + logger.log(Level.INFO, "Trying to launch computer {0} as it has been in demand for too long", c.getNode().getNodeName()); 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()); + if (System.currentTimeMillis() - c.getIdleStartMilliseconds() > + TimeUnit.MILLISECONDS.convert(inDemandDelay, TimeUnit.MINUTES)) { // we've been idle for long enough + logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle too long", c.getNode().getNodeName()); 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 - finishTransition = null; } - return 1; } - return 0; + return 1; } /**