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