Spring Scheduled fixedRate not working properly
Asked Answered
C

2

3

As the title says, I am trying to use the fixedRate paramater of the Scheduled annotation in order to invoke a function every second. Here is the code that I am using:

  //execute once every second
  @Scheduled(fixedRate = 1000)
  private void pullLiveDataFromExternalServer() throws InterruptedException {

    System.err.println("START THREAD " + Thread.currentThread().getId());
    Thread.sleep(5500L);
    System.err.println("END THREAD " + Thread.currentThread().getId());

  }

The way I understand it, the function should print "START THREAD" five times before the first "END THREAD" is printed.

The problem is that the function first prints "START THREAD" and then waits 5.5 seconds, prints "END THREAD", and then goes "START THREAD" and so on... It looks like the scheduler waits for the previous execution to finish before it starts the new execution but that should not be the case for the fixedRate attribute.

I read into it a bit more and found out that the default scheduler for @Scheduled annotation has only one thread, so I created a configuration to change the pool size to 8.

@Component
public class SchedulingConfigurerConfiguration implements SchedulingConfigurer {
  @Override
  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(8);
    taskScheduler.initialize();
    taskRegistrar.setTaskScheduler(taskScheduler);
  }
}

But the behaviour of the fixedRate attribute was no changed and the scheduler was still waiting for the end of the previous execution before starting a new one. Why is this happening ?

The spring boot version that I am using is v1.5.8.RELEASE.

Clearing answered 5/4, 2018 at 11:29 Comment(0)
T
5

It looks like the scheduler waits for the previous execution to finish before it starts the new execution

This is correct and it is the intended behaviour. Each scheduled task, irrespective of fixedRate or fixedDelay, will never run in parallel. This is true even if the invocation takes longer than the configured fixedRate.

Ultimately, fixed rate scheduling results in a call to ScheduledExecutorService.scheduleAtFixedRate. Its javadoc states the following:

If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

If it was possible for multiple invocations of the same scheduled task to run in parallel, the example in your question would exhaust all of the available threads. A new thread would be used every 1000ms and a thread would only become available again every 5500ms.

Tanto answered 5/4, 2018 at 11:53 Comment(3)
How can we run scheduled task in parallel ? Because for my application I need this behaviour.Absorbance
You cannot run multiple occurrences of the same scheduled task in parallelTanto
Yes we can do with using Async and EnableAsync annotation see this : [spring scheduling] (docs.spring.io/spring/docs/5.1.2.RELEASE/…). Go to this section: "7.3. Annotation Support for Scheduling and Asynchronous Execution". I have done this.Absorbance
S
4

The simplest working example with Spring Boot. Configure your application:

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class SpringConfiguration implements AsyncConfigurer {

    public static void main(String[] args) {
        SpringApplication.run(SpringConfiguration.class);
    }

    @Override
    public Executor getAsyncExecutor() {
        return Executors.newScheduledThreadPool(8);
    }

}

Add @Async to your scheduled task:

@Component
public class Task {

    //execute once every second
    @Scheduled(fixedRate = 1000)
    @Async
    public void pullLiveDataFromExternalServer() throws InterruptedException {
        System.err.println("START THREAD " + Thread.currentThread().getId());
        Thread.sleep(5500L);
        System.err.println("END THREAD " + Thread.currentThread().getId());
    }
}
Scene answered 9/7, 2019 at 9:32 Comment(2)
@Async annotation is not necessary, since fixedRate attribute means it will create scheduled executor that will execute method in separate thread anywayBiased
@Biased It is necessary. As the answer of Andy mentioned, by default the scheduler doesn't accept parallel runs, even if you have a big threadpool.Vincentvincenta

© 2022 - 2024 — McMap. All rights reserved.