@Test public void testScheduledTask() throws Exception { int PERIOD = 20; BasicExecutionManager m = new BasicExecutionManager("mycontextid"); final AtomicInteger i = new AtomicInteger(0); ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD, "maxIterations", 5), new Callable<Task<?>>() { @Override public Task<?> call() throws Exception { return new BasicTask<Integer>(new Callable<Integer>() { @Override public Integer call() { log.debug("task running: "+Tasks.current()+" "+Tasks.current().getStatusDetail(false)); return i.incrementAndGet(); }}); }}); log.info("submitting {} {}", t, t.getStatusDetail(false)); m.submit(t); log.info("submitted {} {}", t, t.getStatusDetail(false)); Integer interimResult = (Integer) t.get(); log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)}); assertTrue(i.get() > 0, "i="+i); t.blockUntilEnded(); Integer finalResult = (Integer) t.get(); log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)}); assertEquals(finalResult, (Integer)5); assertEquals(i.get(), 5); }
@Override public void stopReadOnly() { readOnlyRunning = false; if (readOnlyTask!=null) { LOG.debug("Stopping read-only rebinding ("+this+"), mgmt "+managementContext.getManagementNodeId()); readOnlyTask.cancel(true); readOnlyTask.blockUntilEnded(); boolean reallyEnded = Tasks.blockUntilInternalTasksEnded(readOnlyTask, Duration.TEN_SECONDS); if (!reallyEnded) { LOG.warn("Rebind (read-only) tasks took too long to die after interrupt (ignoring): "+readOnlyTask); } readOnlyTask = null; LOG.debug("Stopped read-only rebinding ("+this+"), mgmt "+managementContext.getManagementNodeId()); } }
public void start() { synchronized (startStopMutex) { if (state==ListenerState.RUNNING || (scheduledTask!=null && !scheduledTask.isDone())) { LOG.warn("Request to start "+this+" when already running - "+scheduledTask+"; ignoring"); return; } state = ListenerState.RUNNING; Callable<Task<?>> taskFactory = new Callable<Task<?>>() { @Override public Task<Void> call() { return Tasks.<Void>builder().dynamic(false).displayName("periodic-persister").body(new Callable<Void>() { @Override public Void call() { persistNowSafely(); return null; }}).build(); } }; scheduledTask = (ScheduledTask) executionContext.submit(new ScheduledTask(MutableMap.of("displayName", "scheduled[periodic-persister]", "tags", MutableSet.of(BrooklynTaskTags.TRANSIENT_TASK_TAG)), taskFactory).period(period).delay(period)); } }
/** @return The value of the most recently run task */ @Override public Object get() throws InterruptedException, ExecutionException { blockUntilStarted(); blockUntilFirstScheduleStarted(); return (groovyTruth(recentRun)) ? recentRun.get() : internalFuture.get(); }
@Test public void testScheduledTaskExecutedAtRegularPeriod() throws Exception { final int period = 100; final int numTimestamps = 4; final CountDownLatch latch = new CountDownLatch(1); final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList()); final Stopwatch stopwatch = Stopwatch.createStarted(); Callable<Task<?>> taskFactory = new Callable<Task<?>>() { @Override public Task<?> call() { return new BasicTask<Void>(new Runnable() { @Override public void run() { timestamps.add(stopwatch.elapsed(TimeUnit.MILLISECONDS)); if (timestamps.size() >= numTimestamps) latch.countDown(); }}); }}; ScheduledTask t = new ScheduledTask(taskFactory).delay(1).period(period); em.submit(t); assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); synchronized (timestamps) { long prev = timestamps.get(0); for (long timestamp : timestamps.subList(1, timestamps.size())) { assertTrue(timestamp > prev+period-EARLY_RETURN_GRACE, "timestamps="+timestamps); assertTrue(timestamp < prev+period+MAX_OVERHEAD_MS, "timestamps="+timestamps); prev = timestamp; } } }
@SuppressWarnings("unchecked") protected void schedulePublish(long delay) { if (isRunning() && executorQueued.compareAndSet(false, true)) { long now = System.currentTimeMillis(); delay = Math.max(0, Math.max(delay, (executorTime + MIN_PERIOD_BETWEEN_EXECS_MILLIS) - now)); if (LOG.isTraceEnabled()) LOG.trace("{} scheduling publish in {}ms", this, delay); Runnable job = new PublishJob(); ScheduledTask task = new ScheduledTask(MutableMap.of("delay", Duration.of(delay, TimeUnit.MILLISECONDS)), new BasicTask<Void>(job)); ((EntityInternal)entity).getExecutionContext().submit(task); } }
@Test public void testCanCancelScheduledTask() throws Exception { final int period = 1; final long checkPeriod = 250; final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList()); Callable<Task<?>> taskFactory = new Callable<Task<?>>() { @Override public Task<?> call() { return new BasicTask<Void>(new Runnable() { @Override public void run() { timestamps.add(System.currentTimeMillis()); }}); }}; ScheduledTask t = new ScheduledTask(taskFactory).period(period); em.submit(t); t.cancel(); long cancelTime = System.currentTimeMillis(); int countImmediatelyAfterCancel = timestamps.size(); Thread.sleep(checkPeriod); int countWellAfterCancel = timestamps.size(); // should have at most 1 more execution after cancel log.info("testCanCancelScheduledTask saw "+countImmediatelyAfterCancel+" then cancel then "+countWellAfterCancel+" total"); assertTrue(countWellAfterCancel - countImmediatelyAfterCancel <= 2, "timestamps="+timestamps+"; cancelTime="+cancelTime); }
ScheduledTask task = new ScheduledTask(taskFlags, pollingTaskFactory) .period(pollJob.pollPeriod) .cancelOnException(false); tasks.add(Entities.submit(entity, task)); if (minPeriod==null || (pollJob.pollPeriod.isShorterThan(minPeriod))) {
@Test public void testScheduledTaskExecutedAfterDelay() throws Exception { int delay = 100; final CountDownLatch latch = new CountDownLatch(1); Callable<Task<?>> taskFactory = new Callable<Task<?>>() { @Override public Task<?> call() { return new BasicTask<Void>(new Runnable() { @Override public void run() { latch.countDown(); }}); }}; ScheduledTask t = new ScheduledTask(taskFactory).delay(delay); Stopwatch stopwatch = Stopwatch.createStarted(); em.submit(t); assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); long actualDelay = stopwatch.elapsed(TimeUnit.MILLISECONDS); assertTrue(actualDelay > (delay-EARLY_RETURN_GRACE), "actualDelay="+actualDelay+"; delay="+delay); assertTrue(actualDelay < (delay+MAX_OVERHEAD_MS), "actualDelay="+actualDelay+"; delay="+delay); }
@Test public void testScheduledTaskResubmittedIfExceptionThrownAndCancelOnExceptionFalse() { BasicExecutionManager m = new BasicExecutionManager("mycontextid"); final AtomicInteger calls = new AtomicInteger(0); ScheduledTask t = new ScheduledTask(MutableMap.of("period", Duration.ONE_MILLISECOND, "maxIterations", 5, "cancelOnException", false), new Callable<Task<?>>() { @Override public Task<?> call() throws Exception { return new BasicTask<>(new Callable<Integer>() { @Override public Integer call() { calls.incrementAndGet(); throw new RuntimeException("boo"); }}); }}); m.submit(t); t.blockUntilEnded(); assertEquals(calls.get(), 5, "Expected task to be resubmitted despite throwing an exception"); }
new ScheduledTask(MutableMap.of("displayName", "Periodic read-only rebind"), taskFactory).period(periodicPersistPeriod));
public ScheduledTask delay(long val) { return delay(Duration.millis(val)); }
public ScheduledTask period(long val) { return period(Duration.millis(val)); }
public void stop() { if (log.isDebugEnabled()) log.debug("Stopping poll for {} (using {})", new Object[] {entity, this}); if (!started) { throw new IllegalStateException(String.format("Attempt to stop poller %s of entity %s when not running", this, entity)); } started = false; for (Task<?> task : oneOffTasks) { if (task != null) task.cancel(true); } for (ScheduledTask task : tasks) { if (task != null) task.cancel(); } oneOffTasks.clear(); tasks.clear(); }
boolean result = ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining()); if (!result) return false; ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining()); return true; } else {
cleanupTask = getManagementContext().getExecutionManager().submit(new ScheduledTask( MutableMap.of("displayName", "scheduled[ssh-location cache cleaner]"), cleanupTaskFactory) .period(expiryDuration) .delay(expiryDuration));
ScheduledTask task = new ScheduledTask(MutableMap.of("delay", Duration.of(delay, TimeUnit.MILLISECONDS)), new BasicTask(job)); ((EntityInternal)entity).getExecutionContext().submit(task);
BasicExecutionManager m = new BasicExecutionManager("mycontextid"); final AtomicInteger i = new AtomicInteger(0); ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD), new Callable<Task<?>>() { @Override public Task<?> call() throws Exception { }}); log.info("submitting {} {}", t, t.getStatusDetail(false)); m.submit(t); log.info("submitted {} {}", t, t.getStatusDetail(false)); Integer interimResult = (Integer) t.get(); log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)}); assertTrue(i.get() > 0); t.blockUntilEnded(); Integer finalResult = (Integer) t.get(); log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)}); assertEquals(finalResult, (Integer)5); assertEquals(i.get(), 5);
@SuppressWarnings("unchecked") protected void doStartPolling() { if (scheduledTask == null || scheduledTask.isDone()) { ScheduledTask task = new ScheduledTask(MutableMap.of("period", getPollPeriod(), "displayName", getTaskName()), pollingTaskFactory); scheduledTask = ((EntityInternal)entity).getExecutionContext().submit(task); } }
void stop(Duration timeout, Duration graceTimeoutForSubsequentOperations) { synchronized (startStopMutex) { state = ListenerState.STOPPING; try { if (scheduledTask != null) { CountdownTimer expiry = timeout.countdownTimer(); try { scheduledTask.cancel(false); waitForPendingComplete(expiry.getDurationRemaining().lowerBound(Duration.ZERO).add(graceTimeoutForSubsequentOperations), true); } catch (Exception e) { throw Exceptions.propagate(e); } scheduledTask.blockUntilEnded(expiry.getDurationRemaining().lowerBound(Duration.ZERO).add(graceTimeoutForSubsequentOperations)); scheduledTask.cancel(true); boolean reallyEnded = Tasks.blockUntilInternalTasksEnded(scheduledTask, expiry.getDurationRemaining().lowerBound(Duration.ZERO).add(graceTimeoutForSubsequentOperations)); if (!reallyEnded) { LOG.warn("Persistence tasks took too long to terminate, when stopping persistence, although pending changes were persisted (ignoring): "+scheduledTask); } scheduledTask = null; } // Discard all state that was waiting to be persisted synchronized (this) { deltaCollector = new DeltaCollector(); } } finally { state = ListenerState.STOPPED; } } }