How to change Spring's @Scheduled fixedDelay at runtime

In spring boot, you can use an application property directly!

For example:

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds}000")
private void process() {
    // your impl here
}

Note that you can also have a default value in case the property isn't defined, eg to have a default of "60" (seconds):

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds:60}000")

Other things I discovered:

  • the method must be void
  • the method must have no parameters
  • the method may be private

I found being able to use private visibility handy and used it in this way:

@Service
public class MyService {
    public void process() {
        // do something
    }

    @Scheduled(fixedDelayString = "${my.poll.fixed.delay.seconds}000")
    private void autoProcess() {
        process();
    }
}

Being private, the scheduled method can be local to your service and not become part of your Service's API.

Also, this approach allows the process() method to return a value, which a @Scheduled method may not. For example, your process() method can look like:

public ProcessResult process() {
    // do something and collect information about what was done
    return processResult; 
}

to provide some information about what happened during processing.


You can use a Trigger to dynamically set the next execution time. See my answer here:

Scheduling a job with Spring programmatically (with fixedRate set dynamically)


create interface , something like that:

    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);
}

Next, lets implement Trigger interface that is located at org.springframework.scheduling in the spring-context project.

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);
    }
}

now configuration:

@Configuration
public class DynamicSchedulerConfig {
    @Bean
    public CustomDynamicSchedule getDynamicScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.initialize();
        return  new CustomDynamicSchedule(threadPoolTaskScheduler);
    }
}

and usage:

@EnableScheduling
@Component
public class TestSchedulerComponent {

    @Autowired
    private CustomDynamicSchedule dynamicSchedule;

    @Scheduled(fixedDelay = 5000)
    public void testMethod() {
        dynamicSchedule.delay(1000l);
        dynamicSchedule.increaseDelayInterval(9000l);
        dynamicSchedule.decreaseDelayInterval(5000l);
    }

}