Configurable java.time.Clock on TaskScheduler implementations
Closes gh-25782
This commit is contained in:
parent
5f587faffa
commit
051de3f179
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
|
@ -49,6 +50,15 @@ import org.springframework.lang.Nullable;
|
|||
*/
|
||||
public interface TaskScheduler {
|
||||
|
||||
/**
|
||||
* Return the clock to use for scheduling purposes.
|
||||
* @since 5.3
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
default Clock getClock() {
|
||||
return Clock.systemDefaultZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the given {@link Runnable}, invoking it whenever the trigger
|
||||
* indicates a next execution time.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
|
@ -29,6 +30,16 @@ import org.springframework.lang.Nullable;
|
|||
*/
|
||||
public interface TriggerContext {
|
||||
|
||||
/**
|
||||
* Return the clock to use for trigger calculation.
|
||||
* @since 5.3
|
||||
* @see TaskScheduler#getClock()
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
default Clock getClock() {
|
||||
return Clock.systemDefaultZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last <i>scheduled</i> execution time of the task,
|
||||
* or {@code null} if not scheduled before.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling.concurrent;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
|
@ -89,6 +90,8 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
@Nullable
|
||||
private ErrorHandler errorHandler;
|
||||
|
||||
private Clock clock = Clock.systemDefaultZone();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ConcurrentTaskScheduler,
|
||||
|
|
@ -168,6 +171,21 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock to use for scheduling purposes.
|
||||
* <p>The default clock is the system clock for the default time zone.
|
||||
* @since 5.3
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
|
|
@ -179,7 +197,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
else {
|
||||
ErrorHandler errorHandler =
|
||||
(this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
|
||||
return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
|
||||
return new ReschedulingRunnable(task, trigger, this.clock, this.scheduledExecutor, errorHandler).schedule();
|
||||
}
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
|
|
@ -189,7 +207,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
@ -200,7 +218,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return this.scheduledExecutor.scheduleAtFixedRate(decorateTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
@ -221,7 +239,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
|||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return this.scheduledExecutor.scheduleWithFixedDelay(decorateTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling.concurrent;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
|
@ -47,7 +48,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
|
|||
|
||||
private final Trigger trigger;
|
||||
|
||||
private final SimpleTriggerContext triggerContext = new SimpleTriggerContext();
|
||||
private final SimpleTriggerContext triggerContext;
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
|
|
@ -60,11 +61,12 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
|
|||
private final Object triggerContextMonitor = new Object();
|
||||
|
||||
|
||||
public ReschedulingRunnable(
|
||||
Runnable delegate, Trigger trigger, ScheduledExecutorService executor, ErrorHandler errorHandler) {
|
||||
public ReschedulingRunnable(Runnable delegate, Trigger trigger, Clock clock,
|
||||
ScheduledExecutorService executor, ErrorHandler errorHandler) {
|
||||
|
||||
super(delegate, errorHandler);
|
||||
this.trigger = trigger;
|
||||
this.triggerContext = new SimpleTriggerContext(clock);
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
|
|||
if (this.scheduledExecutionTime == null) {
|
||||
return null;
|
||||
}
|
||||
long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
|
||||
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
|
||||
return this;
|
||||
}
|
||||
|
|
@ -89,9 +91,9 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
Date actualExecutionTime = new Date();
|
||||
Date actualExecutionTime = new Date(this.triggerContext.getClock().millis());
|
||||
super.run();
|
||||
Date completionTime = new Date();
|
||||
Date completionTime = new Date(this.triggerContext.getClock().millis());
|
||||
synchronized (this.triggerContextMonitor) {
|
||||
Assert.state(this.scheduledExecutionTime != null, "No scheduled execution");
|
||||
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling.concurrent;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
|
@ -66,6 +67,8 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
@Nullable
|
||||
private volatile ErrorHandler errorHandler;
|
||||
|
||||
private Clock clock = Clock.systemDefaultZone();
|
||||
|
||||
@Nullable
|
||||
private ScheduledExecutorService scheduledExecutor;
|
||||
|
||||
|
|
@ -110,6 +113,21 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock to use for scheduling purposes.
|
||||
* <p>The default clock is the system clock for the default time zone.
|
||||
* @since 5.3
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ExecutorService initializeExecutor(
|
||||
|
|
@ -310,7 +328,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
if (errorHandler == null) {
|
||||
errorHandler = TaskUtils.getDefaultErrorHandler(true);
|
||||
}
|
||||
return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule();
|
||||
return new ReschedulingRunnable(task, trigger, this.clock, executor, errorHandler).schedule();
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
|
||||
|
|
@ -320,7 +338,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
|
||||
ScheduledExecutorService executor = getScheduledExecutor();
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
@ -332,7 +350,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
|
||||
ScheduledExecutorService executor = getScheduledExecutor();
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
@ -355,7 +373,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
|||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
|
||||
ScheduledExecutorService executor = getScheduledExecutor();
|
||||
long initialDelay = startTime.getTime() - System.currentTimeMillis();
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -470,7 +470,7 @@ public class ScheduledTaskRegistrar implements ScheduledTaskHolder, Initializing
|
|||
}
|
||||
if (this.taskScheduler != null) {
|
||||
if (task.getInitialDelay() > 0) {
|
||||
Date startTime = new Date(System.currentTimeMillis() + task.getInitialDelay());
|
||||
Date startTime = new Date(this.taskScheduler.getClock().millis() + task.getInitialDelay());
|
||||
scheduledTask.future =
|
||||
this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), startTime, task.getInterval());
|
||||
}
|
||||
|
|
@ -519,7 +519,7 @@ public class ScheduledTaskRegistrar implements ScheduledTaskHolder, Initializing
|
|||
}
|
||||
if (this.taskScheduler != null) {
|
||||
if (task.getInitialDelay() > 0) {
|
||||
Date startTime = new Date(System.currentTimeMillis() + task.getInitialDelay());
|
||||
Date startTime = new Date(this.taskScheduler.getClock().millis() + task.getInitialDelay());
|
||||
scheduledTask.future =
|
||||
this.taskScheduler.scheduleWithFixedDelay(task.getRunnable(), startTime, task.getInterval());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ public class PeriodicTrigger implements Trigger {
|
|||
Date lastExecution = triggerContext.lastScheduledExecutionTime();
|
||||
Date lastCompletion = triggerContext.lastCompletionTime();
|
||||
if (lastExecution == null || lastCompletion == null) {
|
||||
return new Date(System.currentTimeMillis() + this.initialDelay);
|
||||
return new Date(triggerContext.getClock().millis() + this.initialDelay);
|
||||
}
|
||||
if (this.fixedRate) {
|
||||
return new Date(lastExecution.getTime() + this.period);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.scheduling.support;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
|
@ -29,6 +30,8 @@ import org.springframework.scheduling.TriggerContext;
|
|||
*/
|
||||
public class SimpleTriggerContext implements TriggerContext {
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
@Nullable
|
||||
private volatile Date lastScheduledExecutionTime;
|
||||
|
||||
|
|
@ -40,23 +43,38 @@ public class SimpleTriggerContext implements TriggerContext {
|
|||
|
||||
|
||||
/**
|
||||
* Create a SimpleTriggerContext with all time values set to {@code null}.
|
||||
* Create a SimpleTriggerContext with all time values set to {@code null},
|
||||
* exposing the system clock for the default time zone.
|
||||
*/
|
||||
public SimpleTriggerContext() {
|
||||
this.clock = Clock.systemDefaultZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SimpleTriggerContext with the given time values.
|
||||
* Create a SimpleTriggerContext with the given time values,
|
||||
* exposing the system clock for the default time zone.
|
||||
* @param lastScheduledExecutionTime last <i>scheduled</i> execution time
|
||||
* @param lastActualExecutionTime last <i>actual</i> execution time
|
||||
* @param lastCompletionTime last completion time
|
||||
*/
|
||||
public SimpleTriggerContext(Date lastScheduledExecutionTime, Date lastActualExecutionTime, Date lastCompletionTime) {
|
||||
this();
|
||||
this.lastScheduledExecutionTime = lastScheduledExecutionTime;
|
||||
this.lastActualExecutionTime = lastActualExecutionTime;
|
||||
this.lastCompletionTime = lastCompletionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SimpleTriggerContext with all time values set to {@code null},
|
||||
* exposing the given clock.
|
||||
* @param clock the clock to use for trigger calculation
|
||||
* @since 5.3
|
||||
* @see #update(Date, Date, Date)
|
||||
*/
|
||||
public SimpleTriggerContext(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update this holder's state with the latest time values.
|
||||
|
|
@ -71,6 +89,11 @@ public class SimpleTriggerContext implements TriggerContext {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Date lastScheduledExecutionTime() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue