问题
In my SpringBoot application, I have a FixedRateScheduledTask. I want to dynamically change the fixed interval upon a refresh event. Note that depending on the processing time, there could be several parallel threads, thanks to Async. Upon a refresh event, I canceled the current ScheduledTask and re-added a new FixedRateTask with new value for interval. Below is my code
@Configuration
@EnableAsync
@EnableScheduling
public class Scheduler implements SchedulingConfigurer, ApplicationListener<EnvironmentChangeEvent> {
private final ConfigParams configParams;
private final MyService myService;
private ScheduledTask scheduledTask;
@Autowired
public Scheduler(ConfigParams schedulerConfigParameters, MyService myService) {
this.configParams = schedulerConfigParameters;
this.myService = myService;
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
log.info("configureTasks :: ");
this.scheduledTask = taskRegistrar.scheduleFixedRateTask(newFixedRateTask());
}
public FixedRateTask newFixedRateTask() {
log.info("newFixedRateTask :: fixedRate {}", configParams.getFixedratedelay());
return new FixedRateTask(myService::processData,
configParams.getFixedratedelay(),
0L);
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent environmentChangeEvent) {
log.info("onApplicationEvent :: {} ", environmentChangeEvent.getKeys());
if (environmentChangeEvent.getKeys().contains("scheduled.fixedratedelay")) {
log.info("config parameter::fixedratedelay::changed");
this.scheduledTask.cancel(); //Problem. It can interrupt the running task
new CustomScheduledTaskRegistrar(newFixedRateTask()).afterPropertiesSet();
}
}
}
public class CustomScheduledTaskRegistrar extends ContextLifecycleScheduledTaskRegistrar {
private final FixedRateTask fixedRateTask;
CustomScheduledTaskRegistrar(FixedRateTask fixedRateTask) {
this.fixedRateTask = fixedRateTask;
}
@Override
public void afterPropertiesSet() {
log.info("afterPropertiesSet");
super.addFixedRateTask(fixedRateTask);
super.afterSingletonsInstantiated();
}
}
@Service
public class MyService {
@Async
public void processData() {
log.info("inside processData {} {}", Thread.currentThread().getName(), LocalDateTime.now());
try {
Thread.sleep(20000L);
} catch (InterruptedException e) {
log.error("InterruptedException ");
}
}
}
I could see that ScheduledTask internally uses a ScheduledFuture and cancel() internally calls future.cancel(mayInterruptIfRunning: true). But I want to gracefully stop the task as my task might contain network calls, db operation etc.
Can that be done?
EDIT
Thanks to issue1 and issue2, I changed my approach and used Annotation based scheduling which helps to me gracefully complete existing threads. Sample application is available here
来源:https://stackoverflow.com/questions/61747502/how-to-stop-a-fixedratescheduledtask-in-spring-without-interrupting-a-running-th