/** * Watch suppliers returned condition. Once Supplier is witnessed in the {@code true} state, the * returned future is completed. Listeners and FutureCallback's executed on the returned future * without a specified pool will run on the polling thread, and so should be kept to a minimum. * * @param p Supplier to provide state for when poll has completed as expected * @return Future to complete once boolean state is witnessed as {@code true} */ public ListenableFuture<?> watch(Supplier<Boolean> p) { ListenableFuture<?> result = runner.watch(p); if (futureWatchdog != null) { futureWatchdog.watch(result); } return result; }
/** * Watch suppliers returned condition. Once Supplier is witnessed in the {@code true} state, the * returned future is completed. Listeners and FutureCallback's executed on the returned future * without a specified pool will run on the polling thread, and so should be kept to a minimum. * * @param p Supplier to provide state for when poll has completed as expected * @return Future to complete once boolean state is witnessed as {@code true} */ public ListenableFuture<?> watch(Supplier<Boolean> p) { ListenableFuture<?> result = runner.watch(p); if (futureWatchdog != null) { futureWatchdog.watch(result); } return result; }
/** * Convert a conventional {@link Future} into a {@link ListenableFuture}. As poller runs it * will check if the provided future has completed. Once it does complete the returned future * will also complete in the exact same way. Canceling the returned future will have NO impact * on the provided future (and thus the use with a timeout is not a concern to interrupting the * provided future). Because this is only checked at poll intervals the returned future's * completion will be delayed by that polling delay. * * @param <T> Type of object returned from future * @param f Future to monitor for completetion * @return ListenableFuture that will provide the result from the source future */ @SuppressWarnings("unchecked") public <T> ListenableFuture<T> watch(Future<? extends T> f) { if ((futureWatchdog == null || f.isDone()) && f instanceof ListenableFuture) { return (ListenableFuture<T>)f; } ListenableFuture<T> result = runner.watch(f); if (futureWatchdog != null) { futureWatchdog.watch(result); } return result; }
/** * Watch a given {@link ListenableFuture} to ensure that it completes within the provided * time limit. If the future is not marked as done by the time limit then it will be * completed by invoking {@link ListenableFuture#cancel(boolean)}. Weather a {@code true} or * {@code false} will be provided to interrupt the running thread is dependent on how this * {@link WatchdogCache} was constructed. * * @param future Future to inspect to ensure completion * @param timeoutInMillis Time in milliseconds that future should be completed within */ public void watch(ListenableFuture<?> future, long timeoutInMillis) { long adjustedTimeout = timeoutInMillis / resolutionMillis; adjustedTimeout *= resolutionMillis; // int division to zero out if (adjustedTimeout != timeoutInMillis) { adjustedTimeout += resolutionMillis; // prefer timing out later rather than early } // attempt around a cheap shortcut if (future == null || future.isDone()) { return; } cachedDogs.computeIfAbsent(adjustedTimeout, watchdogProducer) .watch(future); }
/** * Watch a given {@link ListenableFuture} to ensure that it completes within the provided * time limit. If the future is not marked as done by the time limit then it will be * completed by invoking {@link ListenableFuture#cancel(boolean)}. Weather a {@code true} or * {@code false} will be provided to interrupt the running thread is dependent on how this * {@link WatchdogCache} was constructed. * * @param future Future to inspect to ensure completion * @param timeoutInMillis Time in milliseconds that future should be completed within */ public void watch(ListenableFuture<?> future, long timeoutInMillis) { long adjustedTimeout = timeoutInMillis / resolutionMillis; adjustedTimeout *= resolutionMillis; // int division to zero out if (adjustedTimeout != timeoutInMillis) { adjustedTimeout += resolutionMillis; // prefer timing out later rather than early } // attempt around a cheap shortcut if (future == null || future.isDone()) { return; } cachedDogs.computeIfAbsent(adjustedTimeout, watchdogProducer) .watch(future); }
/** * Convert a conventional {@link Future} into a {@link ListenableFuture}. As poller runs it * will check if the provided future has completed. Once it does complete the returned future * will also complete in the exact same way. Canceling the returned future will have NO impact * on the provided future (and thus the use with a timeout is not a concern to interrupting the * provided future). Because this is only checked at poll intervals the returned future's * completion will be delayed by that polling delay. * * @param <T> Type of object returned from future * @param f Future to monitor for completetion * @return ListenableFuture that will provide the result from the source future */ @SuppressWarnings("unchecked") public <T> ListenableFuture<T> watch(Future<? extends T> f) { if ((futureWatchdog == null || f.isDone()) && f instanceof ListenableFuture) { return (ListenableFuture<T>)f; } ListenableFuture<T> result = runner.watch(f); if (futureWatchdog != null) { futureWatchdog.watch(result); } return result; }
@Test public void alreadyDoneFutureWatchTest() { ListenableFuture<?> future = FutureUtils.immediateResultFuture(null); watchdog.watch(future); assertTrue(watchdog.futures.isEmpty()); }
@Test public void futureFinishTest() { SettableListenableFuture<?> slf = new SettableListenableFuture<>(); watchdog.watch(slf); assertEquals(1, watchdog.futures.size()); slf.setResult(null); assertTrue(watchdog.futures.isEmpty()); }
@Test public void expiredFutureTest() { SettableListenableFuture<?> slf = new SettableListenableFuture<>(); watchdog.watch(slf); TestUtils.blockTillClockAdvances(); assertEquals(1, scheduler.tick(null)); assertTrue(slf.isCancelled()); assertTrue(watchdog.futures.isEmpty()); }
@Test public void isActiveTest() { assertFalse(watchdog.isActive()); ListenableFuture<?> future = FutureUtils.immediateResultFuture(null); watchdog.watch(future); assertFalse(watchdog.isActive()); SettableListenableFuture<?> slf = new SettableListenableFuture<>(); watchdog.watch(slf); assertTrue(watchdog.isActive()); TestUtils.blockTillClockAdvances(); assertEquals(1, scheduler.tick(null)); assertFalse(watchdog.isActive()); }
@Test public void rescheduledFutureCheckTest() throws InterruptedException { long delayTime = 100; // longer than constants DELAY_TIME to ensure we can tick BEFORE the second future times out watchdog = new Watchdog(scheduler, delayTime * 2, true); SettableListenableFuture<?> slf1 = new SettableListenableFuture<>(); watchdog.watch(slf1); TestUtils.sleep(delayTime); SettableListenableFuture<?> slf2 = new SettableListenableFuture<>(); watchdog.watch(slf2); assertEquals(1, scheduler.blockingTick(null)); assertTrue(slf1.isCancelled()); assertFalse(slf2.isCancelled()); assertEquals(1, scheduler.blockingTick(null)); assertTrue(slf1.isCancelled()); assertTrue(slf2.isCancelled()); } }