11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Preconditions; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Throwables; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Callable; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executors; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Future; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ScheduledExecutorService; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.locks.ReentrantLock; 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.Level; 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.Logger; 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.concurrent.GuardedBy; 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Base class for services that can implement {@link #startUp} and {@link #shutDown} but while in 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the "running" state need to perform a periodic task. Subclasses can implement {@link #startUp}, 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #shutDown} and also a {@link #runOneIteration} method that will be executed periodically. 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This class uses the {@link ScheduledExecutorService} returned from {@link #executor} to run 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the {@link #startUp} and {@link #shutDown} methods and also uses that service to schedule the 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #runOneIteration} that will be executed periodically as specified by its 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Scheduler}. When this service is asked to stop via {@link #stop} or {@link #stopAndWait}, 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * it will cancel the periodic task (but not interrupt it) and wait for it to stop before running 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the {@link #shutDown} method. 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Subclasses are guaranteed that the life cycle methods ({@link #runOneIteration}, {@link 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * #startUp} and {@link #shutDown}) will never run concurrently. Notably, if any execution of {@link 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * #runOneIteration} takes longer than its schedule defines, then subsequent executions may start 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * late. Also, all life cycle methods are executed with a lock held, so subclasses can safely 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * modify shared state without additional synchronization necessary for visibility to later 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * executions of the life cycle methods. 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <h3>Usage Example</h3> 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Here is a sketch of a service which crawls a website and uses the scheduling capabilities to 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * rate limit itself. <pre> {@code 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * class CrawlingService extends AbstractScheduledService { 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * private Set<Uri> visited; 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * private Queue<Uri> toCrawl; 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void startUp() throws Exception { 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * toCrawl = readStartingUris(); 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void runOneIteration() throws Exception { 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Uri uri = toCrawl.remove(); 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Collection<Uri> newUris = crawl(uri); 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * visited.add(uri); 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for (Uri newUri : newUris) { 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * if (!visited.contains(newUri)) { toCrawl.add(newUri); } 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void shutDown() throws Exception { 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * saveUris(toCrawl); 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected Scheduler scheduler() { 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS); 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * }}</pre> 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This class uses the life cycle methods to read in a list of starting URIs and save the set of 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * outstanding URIs when shutting down. Also, it takes advantage of the scheduling functionality to 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * rate limit the number of queries we perform. 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic abstract class AbstractScheduledService implements Service { 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Logger logger = Logger.getLogger(AbstractScheduledService.class.getName()); 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A scheduler defines the policy for how the {@link AbstractScheduledService} should run its 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * task. 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Consider using the {@link #newFixedDelaySchedule} and {@link #newFixedRateSchedule} factory 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * methods, these provide {@link Scheduler} instances for the common use case of running the 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * service with a fixed schedule. If more flexibility is needed then consider subclassing the 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link CustomScheduler} abstract class in preference to creating your own {@link Scheduler} 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * implementation. 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public abstract static class Scheduler { 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a {@link Scheduler} that schedules the task using the 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link ScheduledExecutorService#scheduleWithFixedDelay} method. 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param initialDelay the time to delay first execution 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param delay the delay between the termination of one execution and the commencement of the 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * next 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the initialDelay and delay parameters 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Scheduler newFixedDelaySchedule(final long initialDelay, final long delay, 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final TimeUnit unit) { 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new Scheduler() { 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable task) { 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return executor.scheduleWithFixedDelay(task, initialDelay, delay, unit); 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a {@link Scheduler} that schedules the task using the 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link ScheduledExecutorService#scheduleAtFixedRate} method. 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param initialDelay the time to delay first execution 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param period the period between successive executions of the task 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the initialDelay and period parameters 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Scheduler newFixedRateSchedule(final long initialDelay, final long period, 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final TimeUnit unit) { 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new Scheduler() { 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable task) { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return executor.scheduleAtFixedRate(task, initialDelay, period, unit); 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Schedules the task to run on the provided executor on behalf of the service. */ 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert abstract Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable); 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Scheduler() {} 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* use AbstractService for state management */ 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final AbstractService delegate = new AbstractService() { 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // A handle to the running task so that we can stop it when a shutdown has been requested. 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // These two fields are volatile because their values will be accessed from multiple threads. 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private volatile Future<?> runningTask; 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private volatile ScheduledExecutorService executorService; 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // This lock protects the task so we can ensure that none of the template methods (startUp, 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // shutDown or runOneIteration) run concurrently with one another. 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ReentrantLock lock = new ReentrantLock(); 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Runnable task = new Runnable() { 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AbstractScheduledService.this.runOneIteration(); 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert shutDown(); 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Exception ignored) { 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert logger.log(Level.WARNING, 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Error while attempting to shut down the service after failure.", ignored); 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected final void doStart() { 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executorService = executor(); 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executorService.execute(new Runnable() { 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert startUp(); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runningTask = scheduler().schedule(delegate, executorService, task); 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected final void doStop() { 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runningTask.cancel(false); 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executorService.execute(new Runnable() { 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (state() != State.STOPPING) { 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // This means that the state has changed since we were scheduled. This implies that 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // an execution of runOneIteration has thrown an exception and we have transitioned 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // to a failed state, also this means that shutDown has already been called, so we 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // do not want to call it again. 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return; 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert shutDown(); 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Run one iteration of the scheduled task. If any invocation of this method throws an exception, 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the service will transition to the {@link Service.State#FAILED} state and this method will no 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * longer be called. 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract void runOneIteration() throws Exception; 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Start the service. */ 2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract void startUp() throws Exception; 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Stop the service. This is guaranteed not to run concurrently with {@link #runOneIteration}. */ 2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract void shutDown() throws Exception; 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the {@link Scheduler} object used to configure this service. This method will only be 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * called once. 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract Scheduler scheduler(); 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the {@link ScheduledExecutorService} that will be used to execute the {@link #startUp}, 2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #runOneIteration} and {@link #shutDown} methods. The executor will not be 2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link ScheduledExecutorService#shutdown} when this service stops. Subclasses may override this 2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * method to use a custom {@link ScheduledExecutorService} instance. 2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>By default this returns a new {@link ScheduledExecutorService} with a single thread thread 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * pool. This method will only be called once. 2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected ScheduledExecutorService executor() { 2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Executors.newSingleThreadScheduledExecutor(); 2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public String toString() { 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getClass().getSimpleName() + " [" + state() + "]"; 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // We override instead of using ForwardingService so that these can be final. 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final ListenableFuture<State> start() { 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.start(); 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State startAndWait() { 2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.startAndWait(); 2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final boolean isRunning() { 2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.isRunning(); 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State state() { 2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.state(); 2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final ListenableFuture<State> stop() { 2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.stop(); 2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State stopAndWait() { 2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.stopAndWait(); 2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A {@link Scheduler} that provides a convenient way for the {@link AbstractScheduledService} to 2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * use a dynamically changing schedule. After every execution of the task, assuming it hasn't 2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * been cancelled, the {@link #getNextSchedule} method will be called. 2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Beta 3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public abstract static class CustomScheduler extends Scheduler { 3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A callable class that can reschedule itself using a {@link CustomScheduler}. 3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private class ReschedulableCallable extends ForwardingFuture<Void> implements Callable<Void> { 3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The underlying task. */ 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Runnable wrappedRunnable; 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The executor on which this Callable will be scheduled. */ 3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ScheduledExecutorService executor; 3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The service that is managing this callable. This is used so that failure can be 3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * reported properly. 3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final AbstractService service; 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This lock is used to ensure safe and correct cancellation, it ensures that a new task is 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * not scheduled while a cancel is ongoing. Also it protects the currentFuture variable to 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * ensure that it is assigned atomically with being scheduled. 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ReentrantLock lock = new ReentrantLock(); 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The future that represents the next execution of this task.*/ 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @GuardedBy("lock") 3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Future<Void> currentFuture; 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ReschedulableCallable(AbstractService service, ScheduledExecutorService executor, 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable) { 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.wrappedRunnable = runnable; 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.executor = executor; 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.service = service; 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Void call() throws Exception { 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert wrappedRunnable.run(); 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert reschedule(); 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Atomically reschedules this task and assigns the new future to {@link #currentFuture}. 3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void reschedule() { 3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // We reschedule ourselves with a lock held for two reasons. 1. we want to make sure that 3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // cancel calls cancel on the correct future. 2. we want to make sure that the assignment 3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // to currentFuture doesn't race with itself so that currentFuture is assigned in the 3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // correct order. 3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (currentFuture == null || !currentFuture.isCancelled()) { 3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final Schedule schedule = CustomScheduler.this.getNextSchedule(); 3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert currentFuture = executor.schedule(this, schedule.delay, schedule.unit); 3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable e) { 3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If an exception is thrown by the subclass then we need to make sure that the service 3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // notices and transitions to the FAILED state. We do it by calling notifyFailed directly 3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // because the service does not monitor the state of the future so if the exception is not 3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // caught and forwarded to the service the task would stop executing but the service would 3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // have no idea. 3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyFailed(e); 3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // N.B. Only protect cancel and isCancelled because those are the only methods that are 3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // invoked by the AbstractScheduledService. 3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public boolean cancel(boolean mayInterruptIfRunning) { 3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Ensure that a task cannot be rescheduled while a cancel is ongoing. 3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return currentFuture.cancel(mayInterruptIfRunning); 3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected Future<Void> delegate() { 3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnsupportedOperationException("Only cancel is supported by this future"); 3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable) { 3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ReschedulableCallable task = new ReschedulableCallable(service, executor, runnable); 3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert task.reschedule(); 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return task; 3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A value object that represents an absolute delay until a task should be invoked. 4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Beta 4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected static final class Schedule { 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final long delay; 4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final TimeUnit unit; 4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param delay the time from now to delay execution 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the delay parameter 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Schedule(long delay, TimeUnit unit) { 4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.delay = delay; 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.unit = Preconditions.checkNotNull(unit); 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Calculates the time at which to next invoke the task. 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This is guaranteed to be called immediately after the task has completed an iteration and 4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * on the same thread as the previous execution of {@link 4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * AbstractScheduledService#runOneIteration}. 4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return a schedule that defines the delay before the next execution. 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract Schedule getNextSchedule() throws Exception; 4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 434