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 193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport static com.google.common.util.concurrent.MoreExecutors.directExecutor; 203ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Preconditions; 230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.base.Supplier; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Throwables; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Callable; 277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Executor; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executors; 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Future; 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ScheduledExecutorService; 317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.ThreadFactory; 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit; 330888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.TimeoutException; 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.locks.ReentrantLock; 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.Level; 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.Logger; 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.concurrent.GuardedBy; 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Base class for services that can implement {@link #startUp} and {@link #shutDown} but while in 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the "running" state need to perform a periodic task. Subclasses can implement {@link #startUp}, 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #shutDown} and also a {@link #runOneIteration} method that will be executed periodically. 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This class uses the {@link ScheduledExecutorService} returned from {@link #executor} to run 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the {@link #startUp} and {@link #shutDown} methods and also uses that service to schedule the 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #runOneIteration} that will be executed periodically as specified by its 480888a09821a98ac0680fad765217302858e70fa4Paul Duffin * {@link Scheduler}. When this service is asked to stop via {@link #stopAsync} it will cancel the 490888a09821a98ac0680fad765217302858e70fa4Paul Duffin * periodic task (but not interrupt it) and wait for it to stop before running the 500888a09821a98ac0680fad765217302858e70fa4Paul Duffin * {@link #shutDown} method. 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Subclasses are guaranteed that the life cycle methods ({@link #runOneIteration}, {@link 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * #startUp} and {@link #shutDown}) will never run concurrently. Notably, if any execution of {@link 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * #runOneIteration} takes longer than its schedule defines, then subsequent executions may start 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * late. Also, all life cycle methods are executed with a lock held, so subclasses can safely 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * modify shared state without additional synchronization necessary for visibility to later 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * executions of the life cycle methods. 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <h3>Usage Example</h3> 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 610888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>Here is a sketch of a service which crawls a website and uses the scheduling capabilities to 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * rate limit itself. <pre> {@code 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * class CrawlingService extends AbstractScheduledService { 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * private Set<Uri> visited; 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * private Queue<Uri> toCrawl; 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void startUp() throws Exception { 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * toCrawl = readStartingUris(); 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void runOneIteration() throws Exception { 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Uri uri = toCrawl.remove(); 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Collection<Uri> newUris = crawl(uri); 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * visited.add(uri); 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for (Uri newUri : newUris) { 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * if (!visited.contains(newUri)) { toCrawl.add(newUri); } 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected void shutDown() throws Exception { 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * saveUris(toCrawl); 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * protected Scheduler scheduler() { 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS); 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * }}</pre> 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 880888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>This class uses the life cycle methods to read in a list of starting URIs and save the set of 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * outstanding URIs when shutting down. Also, it takes advantage of the scheduling functionality to 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * rate limit the number of queries we perform. 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic abstract class AbstractScheduledService implements Service { 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Logger logger = Logger.getLogger(AbstractScheduledService.class.getName()); 980888a09821a98ac0680fad765217302858e70fa4Paul Duffin 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A scheduler defines the policy for how the {@link AbstractScheduledService} should run its 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * task. 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Consider using the {@link #newFixedDelaySchedule} and {@link #newFixedRateSchedule} factory 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * methods, these provide {@link Scheduler} instances for the common use case of running the 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin * service with a fixed schedule. If more flexibility is needed then consider subclassing 1067dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@link CustomScheduler}. 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public abstract static class Scheduler { 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a {@link Scheduler} that schedules the task using the 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link ScheduledExecutorService#scheduleWithFixedDelay} method. 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param initialDelay the time to delay first execution 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param delay the delay between the termination of one execution and the commencement of the 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * next 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the initialDelay and delay parameters 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1210888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static Scheduler newFixedDelaySchedule(final long initialDelay, final long delay, 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final TimeUnit unit) { 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new Scheduler() { 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable task) { 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return executor.scheduleWithFixedDelay(task, initialDelay, delay, unit); 1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a {@link Scheduler} that schedules the task using the 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link ScheduledExecutorService#scheduleAtFixedRate} method. 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param initialDelay the time to delay first execution 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param period the period between successive executions of the task 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the initialDelay and period parameters 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1400888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static Scheduler newFixedRateSchedule(final long initialDelay, final long period, 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final TimeUnit unit) { 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new Scheduler() { 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable task) { 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return executor.scheduleAtFixedRate(task, initialDelay, period, unit); 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1500888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Schedules the task to run on the provided executor on behalf of the service. */ 1520888a09821a98ac0680fad765217302858e70fa4Paul Duffin abstract Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable); 1540888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Scheduler() {} 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1570888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* use AbstractService for state management */ 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final AbstractService delegate = new AbstractService() { 1600888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // A handle to the running task so that we can stop it when a shutdown has been requested. 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // These two fields are volatile because their values will be accessed from multiple threads. 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private volatile Future<?> runningTask; 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private volatile ScheduledExecutorService executorService; 1650888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // This lock protects the task so we can ensure that none of the template methods (startUp, 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // shutDown or runOneIteration) run concurrently with one another. 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ReentrantLock lock = new ReentrantLock(); 1690888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Runnable task = new Runnable() { 1710888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AbstractScheduledService.this.runOneIteration(); 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert shutDown(); 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Exception ignored) { 1790888a09821a98ac0680fad765217302858e70fa4Paul Duffin logger.log(Level.WARNING, 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Error while attempting to shut down the service after failure.", ignored); 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1890888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1900888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected final void doStart() { 1910888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService = MoreExecutors.renamingDecorator(executor(), new Supplier<String>() { 1920888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public String get() { 1930888a09821a98ac0680fad765217302858e70fa4Paul Duffin return serviceName() + " " + state(); 1940888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin }); 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executorService.execute(new Runnable() { 1970888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert startUp(); 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runningTask = scheduler().schedule(delegate, executorService, task); 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2130888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected final void doStop() { 2140888a09821a98ac0680fad765217302858e70fa4Paul Duffin runningTask.cancel(false); 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executorService.execute(new Runnable() { 2160888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (state() != State.STOPPING) { 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // This means that the state has changed since we were scheduled. This implies that 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // an execution of runOneIteration has thrown an exception and we have transitioned 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // to a failed state, also this means that shutDown has already been called, so we 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // do not want to call it again. 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return; 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert shutDown(); 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable t) { 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyFailed(t); 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw Throwables.propagate(t); 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 2400888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2417dd252788645e940eada959bdde927426e2531c9Paul Duffin /** Constructor for use by subclasses. */ 2427dd252788645e940eada959bdde927426e2531c9Paul Duffin protected AbstractScheduledService() {} 2437dd252788645e940eada959bdde927426e2531c9Paul Duffin 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Run one iteration of the scheduled task. If any invocation of this method throws an exception, 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the service will transition to the {@link Service.State#FAILED} state and this method will no 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * longer be called. 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract void runOneIteration() throws Exception; 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2517dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2527dd252788645e940eada959bdde927426e2531c9Paul Duffin * Start the service. 2537dd252788645e940eada959bdde927426e2531c9Paul Duffin * 2547dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>By default this method does nothing. 2557dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2567dd252788645e940eada959bdde927426e2531c9Paul Duffin protected void startUp() throws Exception {} 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2587dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2597dd252788645e940eada959bdde927426e2531c9Paul Duffin * Stop the service. This is guaranteed not to run concurrently with {@link #runOneIteration}. 2607dd252788645e940eada959bdde927426e2531c9Paul Duffin * 2617dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>By default this method does nothing. 2627dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2637dd252788645e940eada959bdde927426e2531c9Paul Duffin protected void shutDown() throws Exception {} 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the {@link Scheduler} object used to configure this service. This method will only be 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * called once. 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract Scheduler scheduler(); 2700888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the {@link ScheduledExecutorService} that will be used to execute the {@link #startUp}, 2737dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@link #runOneIteration} and {@link #shutDown} methods. If this method is overridden the 2747dd252788645e940eada959bdde927426e2531c9Paul Duffin * executor will not be {@linkplain ScheduledExecutorService#shutdown shutdown} when this 2757dd252788645e940eada959bdde927426e2531c9Paul Duffin * service {@linkplain Service.State#TERMINATED terminates} or 2767dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@linkplain Service.State#TERMINATED fails}. Subclasses may override this method to supply a 2777dd252788645e940eada959bdde927426e2531c9Paul Duffin * custom {@link ScheduledExecutorService} instance. This method is guaranteed to only be called 2787dd252788645e940eada959bdde927426e2531c9Paul Duffin * once. 2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>By default this returns a new {@link ScheduledExecutorService} with a single thread thread 2817dd252788645e940eada959bdde927426e2531c9Paul Duffin * pool that sets the name of the thread to the {@linkplain #serviceName() service name}. 2827dd252788645e940eada959bdde927426e2531c9Paul Duffin * Also, the pool will be {@linkplain ScheduledExecutorService#shutdown() shut down} when the 2837dd252788645e940eada959bdde927426e2531c9Paul Duffin * service {@linkplain Service.State#TERMINATED terminates} or 2847dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@linkplain Service.State#TERMINATED fails}. 2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected ScheduledExecutorService executor() { 2870888a09821a98ac0680fad765217302858e70fa4Paul Duffin final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( 2880888a09821a98ac0680fad765217302858e70fa4Paul Duffin new ThreadFactory() { 2890888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Thread newThread(Runnable runnable) { 2907dd252788645e940eada959bdde927426e2531c9Paul Duffin return MoreExecutors.newThread(serviceName(), runnable); 2917dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2927dd252788645e940eada959bdde927426e2531c9Paul Duffin }); 2937dd252788645e940eada959bdde927426e2531c9Paul Duffin // Add a listener to shutdown the executor after the service is stopped. This ensures that the 2947dd252788645e940eada959bdde927426e2531c9Paul Duffin // JVM shutdown will not be prevented from exiting after this service has stopped or failed. 2957dd252788645e940eada959bdde927426e2531c9Paul Duffin // Technically this listener is added after start() was called so it is a little gross, but it 2967dd252788645e940eada959bdde927426e2531c9Paul Duffin // is called within doStart() so we know that the service cannot terminate or fail concurrently 2977dd252788645e940eada959bdde927426e2531c9Paul Duffin // with adding this listener so it is impossible to miss an event that we are interested in. 2987dd252788645e940eada959bdde927426e2531c9Paul Duffin addListener(new Listener() { 2990888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void terminated(State from) { 3007dd252788645e940eada959bdde927426e2531c9Paul Duffin executor.shutdown(); 3017dd252788645e940eada959bdde927426e2531c9Paul Duffin } 3020888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void failed(State from, Throwable failure) { 3037dd252788645e940eada959bdde927426e2531c9Paul Duffin executor.shutdown(); 3043ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin } 3053ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin }, directExecutor()); 3067dd252788645e940eada959bdde927426e2531c9Paul Duffin return executor; 3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3097dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 3107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Returns the name of this service. {@link AbstractScheduledService} may include the name in 3117dd252788645e940eada959bdde927426e2531c9Paul Duffin * debugging output. 3127dd252788645e940eada959bdde927426e2531c9Paul Duffin * 3137dd252788645e940eada959bdde927426e2531c9Paul Duffin * @since 14.0 3147dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 3157dd252788645e940eada959bdde927426e2531c9Paul Duffin protected String serviceName() { 3167dd252788645e940eada959bdde927426e2531c9Paul Duffin return getClass().getSimpleName(); 3177dd252788645e940eada959bdde927426e2531c9Paul Duffin } 3180888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public String toString() { 3207dd252788645e940eada959bdde927426e2531c9Paul Duffin return serviceName() + " [" + state() + "]"; 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3230888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final boolean isRunning() { 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.isRunning(); 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3270888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final State state() { 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delegate.state(); 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3317dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 3327dd252788645e940eada959bdde927426e2531c9Paul Duffin * @since 13.0 3337dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 3340888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final void addListener(Listener listener, Executor executor) { 3357dd252788645e940eada959bdde927426e2531c9Paul Duffin delegate.addListener(listener, executor); 3367dd252788645e940eada959bdde927426e2531c9Paul Duffin } 3370888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3387dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 3397dd252788645e940eada959bdde927426e2531c9Paul Duffin * @since 14.0 3407dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 3410888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final Throwable failureCause() { 3427dd252788645e940eada959bdde927426e2531c9Paul Duffin return delegate.failureCause(); 3437dd252788645e940eada959bdde927426e2531c9Paul Duffin } 3440888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3450888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3460888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3470888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3480888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final Service startAsync() { 3490888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.startAsync(); 3500888a09821a98ac0680fad765217302858e70fa4Paul Duffin return this; 3510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3520888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3530888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3540888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3550888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3560888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final Service stopAsync() { 3570888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.stopAsync(); 3580888a09821a98ac0680fad765217302858e70fa4Paul Duffin return this; 3590888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3600888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3610888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3620888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3630888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3640888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final void awaitRunning() { 3650888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.awaitRunning(); 3660888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3670888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3690888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3700888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3710888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 3720888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.awaitRunning(timeout, unit); 3730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3740888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3750888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3760888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3770888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3780888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final void awaitTerminated() { 3790888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.awaitTerminated(); 3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3810888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3820888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3830888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @since 15.0 3840888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3850888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 3860888a09821a98ac0680fad765217302858e70fa4Paul Duffin delegate.awaitTerminated(timeout, unit); 3870888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3880888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A {@link Scheduler} that provides a convenient way for the {@link AbstractScheduledService} to 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * use a dynamically changing schedule. After every execution of the task, assuming it hasn't 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * been cancelled, the {@link #getNextSchedule} method will be called. 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 3960888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Beta 3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public abstract static class CustomScheduler extends Scheduler { 3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A callable class that can reschedule itself using a {@link CustomScheduler}. 4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private class ReschedulableCallable extends ForwardingFuture<Void> implements Callable<Void> { 4040888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The underlying task. */ 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Runnable wrappedRunnable; 4070888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The executor on which this Callable will be scheduled. */ 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ScheduledExecutorService executor; 4100888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The service that is managing this callable. This is used so that failure can be 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * reported properly. 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final AbstractService service; 4160888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This lock is used to ensure safe and correct cancellation, it ensures that a new task is 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * not scheduled while a cancel is ongoing. Also it protects the currentFuture variable to 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * ensure that it is assigned atomically with being scheduled. 4210888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ReentrantLock lock = new ReentrantLock(); 4230888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** The future that represents the next execution of this task.*/ 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @GuardedBy("lock") 4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Future<Void> currentFuture; 4270888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4280888a09821a98ac0680fad765217302858e70fa4Paul Duffin ReschedulableCallable(AbstractService service, ScheduledExecutorService executor, 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable) { 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.wrappedRunnable = runnable; 4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.executor = executor; 4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.service = service; 4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4340888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4350888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Void call() throws Exception { 4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert wrappedRunnable.run(); 4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert reschedule(); 4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Atomically reschedules this task and assigns the new future to {@link #currentFuture}. 4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void reschedule() { 4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // We reschedule ourselves with a lock held for two reasons. 1. we want to make sure that 4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // cancel calls cancel on the correct future. 2. we want to make sure that the assignment 4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // to currentFuture doesn't race with itself so that currentFuture is assigned in the 4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // correct order. 4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (currentFuture == null || !currentFuture.isCancelled()) { 4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final Schedule schedule = CustomScheduler.this.getNextSchedule(); 4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert currentFuture = executor.schedule(this, schedule.delay, schedule.unit); 4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (Throwable e) { 4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If an exception is thrown by the subclass then we need to make sure that the service 4581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // notices and transitions to the FAILED state. We do it by calling notifyFailed directly 4591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // because the service does not monitor the state of the future so if the exception is not 4601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // caught and forwarded to the service the task would stop executing but the service would 4611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // have no idea. 4621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyFailed(e); 4631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 4641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 4651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4670888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // N.B. Only protect cancel and isCancelled because those are the only methods that are 4691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // invoked by the AbstractScheduledService. 4701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public boolean cancel(boolean mayInterruptIfRunning) { 4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Ensure that a task cannot be rescheduled while a cancel is ongoing. 4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.lock(); 4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return currentFuture.cancel(mayInterruptIfRunning); 4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lock.unlock(); 4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected Future<Void> delegate() { 4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnsupportedOperationException("Only cancel is supported by this future"); 4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4860888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 4880888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Future<?> schedule(AbstractService service, ScheduledExecutorService executor, 4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Runnable runnable) { 4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ReschedulableCallable task = new ReschedulableCallable(service, executor, runnable); 4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert task.reschedule(); 4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return task; 4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4940888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A value object that represents an absolute delay until a task should be invoked. 4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg 4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Beta 5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected static final class Schedule { 5030888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final long delay; 5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final TimeUnit unit; 5060888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param delay the time from now to delay execution 5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param unit the time unit of the delay parameter 5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Schedule(long delay, TimeUnit unit) { 5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.delay = delay; 5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.unit = Preconditions.checkNotNull(unit); 5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5160888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 5181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Calculates the time at which to next invoke the task. 5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This is guaranteed to be called immediately after the task has completed an iteration and 5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * on the same thread as the previous execution of {@link 5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * AbstractScheduledService#runOneIteration}. 5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return a schedule that defines the delay before the next execution. 5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract Schedule getNextSchedule() throws Exception; 5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 529