8

If i want a method to repeat async, can i use @Scheduled and @Async together ?

@Async
@Scheduled(fixedDelay = x)
public void doSomethingEveryXMinuteAsync() { 
  // action 
}

or is there another standard way to achive this ?

Anders Pedersen
  • 2,255
  • 4
  • 25
  • 49

5 Answers5

9

There is no need to use @Async. Just use fixedRate attribute of @Scheduled instead of fixedDelay. Spring will make another invocation on the method after the given time regardless of any call is already being processed.

UPDATE:

Apparently fixedRate attribute does not enforce a scheduled method to be called asynchronously and increasing pool size of scheduler task executor only enables asynchronous execution of independent @Scheduled methods. Even putting @Async on the method does not make it work as OP has asked.

ScheduledAnnotationBeanPostProcessor just creates a Runnable from the @Scheduled method and does not create any pointcut as @Async method processor would. ScheduledThreadPoolExecutor waits until Runnable#run() is finished and sets the next execution time using the start time and the fixed rate. So if the method call takes more time than the scheduled time, the next task is triggered right after the previous call is finished.

An easy solution would be extracting the actual method into another class as a @Async method and calling this method from the @Scheduled method.

Yuqu
  • 255
  • 1
  • 7
  • so if i have two @Scheduled task with the same fixedRate, they will run at the same time ? – Anders Pedersen Feb 27 '17 at 11:16
  • Default thread pool size is 1. You need to configure a custom Executor in order to make your methods to run in parallel. Be aware of that this won't guarantee you to make your methods to start to run "exactly at the same time". Check this answer for Executor configuration: http://stackoverflow.com/questions/37344801/spring-scheduler-parallel-running – Yuqu Feb 28 '17 at 07:02
  • 1
    Well no, as you can see at this ticket (https://jira.spring.io/browse/SPR-12935) you need @Async to run your tasks with real fixedRate. Otherwise, it just adds it to the queue. Just try to run a task with fixedRate=1000 and Thread.sleep(5000) inside – ottercoder Dec 11 '17 at 10:53
  • @ottercoder I've tried with `@Async` but it does not even work using `@Async`. Please check the updated answer. – Yuqu Dec 12 '17 at 14:43
  • "extracting the actual method into another class as a @ Async method" it must be in another class or just can be in another method by @ Async annotation in same class? – mshzmkot Mar 22 '20 at 09:08
  • It should be in another class. If not, `@Scheduled` method cannot trigger `@Async` behaviour (invocations of the another method in the same class won't be able to trigger methods on AOP proxy class). – Yuqu Mar 24 '20 at 08:53
2

Implement SchedulingConfigurer and override configureTasks method. Define poolsize more than one, It will work as you are expecting.

Sarang
  • 422
  • 5
  • 11
  • Yes. I initially find all scheduled tasks run in series, because ThreadPoolTaskScheduler has a size one. Make sure it has a size more than one, like the following with size 10: @Bean public TaskScheduler poolScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setThreadNamePrefix("ThreadPoolTaskScheduler"); scheduler.setPoolSize(10); scheduler.initialize(); return scheduler; } – TGU Jun 04 '20 at 18:40
2

You should configure implementing SchedulingConfigurer:

@Configuration
@EnableScheduling
public class ScheduledConfiguration implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar)
    {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);
        threadPoolTaskScheduler.setThreadNamePrefix("your-scheduler-");
        threadPoolTaskScheduler.initialize();

        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

With this code you achieve parallel execution of your method which is annotated with @Scheduled.

Heril Muratovic
  • 1,940
  • 6
  • 25
  • 46
1

You may also set the property:

spring.task.scheduling.pool.size
Doctor Parameter
  • 1,202
  • 2
  • 15
  • 21
0
  1. @Async and @Scheduled method shouldn't be in a same class.
  2. follow the manual and add AsyncConfigurerhttps://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableAsync.html
gotouei
  • 1
  • 2