У меня есть требование запустить пакетное задание с фиксированным интервалом и иметь возможность изменять время выполнения этого пакетного задания во время выполнения. Для этого я встретил аннотацию @Scheduled, представленную в рамках Spring. Но я не уверен, как изменить значение fixedDelay во время выполнения. Я немного искал, но не нашел ничего полезного.
Как изменить Spring @Scheduled fixedDelay во время выполнения
Ответ 1
Вы можете использовать Trigger
для динамического задания следующего времени выполнения. См. Мой ответ здесь:
Планирование задания с помощью Spring программным способом (с установкой fixedRate динамически)
Ответ 2
В загрузке spring вы можете напрямую использовать свойство приложения.
Например:
@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds}000")
private void process() {
// your impl here
}
Обратите внимание, что вы также можете иметь значение по умолчанию, если свойство не определено, например, чтобы иметь значение по умолчанию "60" (в секундах):
@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds:60}000")
Другие вещи, которые я обнаружил:
- метод должен быть недействительным
- метод не должен иметь параметров
- метод может быть
private
Я обнаружил, что можно использовать видимость private
и использовать его таким образом:
@Service
public class MyService {
public void process() {
// do something
}
@Scheduled(fixedDelayString = "${my.poll.fixed.delay.seconds}000")
private void autoProcess() {
process();
}
}
Будучи private
, метод планирования может быть локальным для вашей службы и не стать частью вашего API-сервисов.
Кроме того, этот подход позволяет методу process()
возвращать значение, которое может не использовать метод @Scheduled
. Например, ваш метод process()
может выглядеть так:
public ProcessResult process() {
// do something and collect information about what was done
return processResult;
}
чтобы предоставить некоторую информацию о том, что произошло во время обработки.
Ответ 3
создать интерфейс, что-то вроде этого:
public abstract class DynamicSchedule{
/**
* Delays scheduler
* @param milliseconds - the time to delay scheduler.
*/
abstract void delay(Long milliseconds);
/**
* Decreases delay period
* @param milliseconds - the time to decrease delay period.
*/
abstract void decreaseDelayInterval(Long milliseconds);
/**
* Increases delay period
* @param milliseconds - the time to increase dela period
*/
abstract void increaseDelayInterval(Long milliseconds);
}
Далее, давайте реализуем интерфейс Trigger, который расположен в org.springframework.scheduling в проекте Spring-Context.
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private TaskScheduler taskScheduler;
private ScheduledFuture<?> schedulerFuture;
/**
* milliseconds
*/
private long delayInterval;
public CustomDynamicSchedule(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
@Override
public void increaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public void decreaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval -= delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public void delay(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval = delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
сейчас конфигурация:
@Configuration
public class DynamicSchedulerConfig {
@Bean
public CustomDynamicSchedule getDynamicScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.initialize();
return new CustomDynamicSchedule(threadPoolTaskScheduler);
}
}
и использование:
@EnableScheduling
@Component
public class TestSchedulerComponent {
@Autowired
private CustomDynamicSchedule dynamicSchedule;
@Scheduled(fixedDelay = 5000)
public void testMethod() {
dynamicSchedule.delay(1000l);
dynamicSchedule.increaseDelayInterval(9000l);
dynamicSchedule.decreaseDelayInterval(5000l);
}
}
Ответ 4
AFAIK API Spring не позволит вам получить доступ к внутренним компонентам, которые вам нужны для изменения триггера. Но вместо этого вы можете настроить вручную beans:
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<property name="startDelay" value="10000" />
<property name="repeatInterval" value="50000" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
</list>
</property>
</bean>
Затем, как описано в SchedulerFactoryBean:
Для динамической регистрации заданий во время выполнения используйте ссылку bean для этот SchedulerFactoryBean, чтобы получить прямой доступ к Quartz Scheduler (
org.quartz.Scheduler
). Это позволяет вам создавать новые заданий и триггеров, а также для контроля и мониторинга всего Планировщик.