2

I have the following code using @EnableScheduling and @EnableAsync together:

@Configuration
@EnableAsync
@EnableScheduling
public class PollingAgent {

    @Async
    @Scheduled(fixedRate=INTERVAL_RATE, initialDelay = 10000) //setting an initial delay to let the beans get loaded
    void checkAvailableAndStartJob() {
        if(m_messageOnDemand) {
            try {
                LOGGER.info("check job messages and start job if possible");
                jobIdOnDemandSubscriber.StartJobIfMessageAvailable(m_applicationContext);
            } catch (Exception e) {
                LOGGER.info("Scheduler run failed: " + e.getMessage());
            }
        }
    }
}

I think even without @EnableAsync and @Async, checkAvailableAndStartJob will be triggered asynchronously on a different thread, why we need them?

lightrek
  • 951
  • 3
  • 14
  • 30
  • Maybe this post can help you too. https://stackoverflow.com/questions/54801769/what-purpose-of-the-spring-enableasync-annotation-and-how-to-use-it-well – Robert Pho Aug 09 '22 at 01:18
  • Thanks! but if I only use `@EnableScheduling` without `@EnableAsync`, how can the scheduled task run? (I suppose the scheduled task should run on a separate thread asyncrously) – lightrek Aug 09 '22 at 14:11
  • Similar question: https://stackoverflow.com/questions/14623092/using-spring-scheduled-and-async-together – nyg Mar 19 '23 at 22:08

1 Answers1

1

I do not think @Async and @Scheduled are meant to be used on the same method, even if it does work.

  • First, a @Scheduled method should return void and have no parameters (for obvious reasons), whereas an @Async method can have parameters and can return a value (i.e. Future<?>).

  • Second, @EnableScheduling will look for a TaskScheduler to execute the @Scheduled methods, whereas @EnableAsync will look for a TaskExecutor to execute the @Async methods. The two are different things, Spring doc says:

    The Spring Framework provides abstractions for the asynchronous execution and scheduling of tasks with the TaskExecutor and TaskScheduler interfaces, respectively.


However, it is possible to use @EnableAsync and @EnableScheduling on the same @Configuration class, depending on what you want to do. For example, the Spring documentation shows this example:

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {}

It can indeed be a bit confusing at first, but as they mention:

You can pick and choose the relevant annotations for your application. For example, if you need only support for @Scheduled, you can omit @EnableAsync.

The example is probably there if you want to do something like:

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {

    @Async // requires @EnableAsync
    public Future<String> asyncMethod(String data) {
        // do something
        return CompletableFuture.completedFuture("finished");
    }

    @Scheduled(fixedRate = 1_000) // requires @EnableScheduling
    public void everySecond() {
        // do something
    }
}

As for your question, how can the scheduled task run?, the doc for @EnableScheduling says:

By default, Spring will search for an associated scheduler definition: either a unique TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; (…). If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.

So, if you have multiple @Scheduled methods and want them to be able to execute in parallel, you need to define a TaskScheduler with a pool size greater than one:

@Configuration
@EnableScheduling
public class SchedulerContext {

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("sched-task-");
        scheduler.setPoolSize(10); // 1 is the default value
        scheduler.initialize();
        return scheduler;
    }
}
nyg
  • 2,380
  • 3
  • 25
  • 40