How do I tell my Spring scheduled method to run using a specific executor?
For example, this is one of my spring scheduler method,
#Scheduled(fixedRate=1000)
public void scheduleJobs(){
doThese();
}
And here are the 2 executors defined in my Java config:
#Bean
public Executor taskScheduler() {
ThreadPoolTaskScheduler t = new ThreadPoolTaskScheduler();
t.setPoolSize(2);
t.setThreadNamePrefix("taskScheduler - ");
t.initialize();
return t;
}
#Bean
public Executor newTaskScheduler() {
ThreadPoolTaskScheduler t = new ThreadPoolTaskScheduler();
t.setPoolSize(2);
t.setThreadNamePrefix("newTaskScheduler - ");
t.initialize();
return t;
}
When the scheduled method is running I can see it is using taskScheduler executor. How to tell it to run using newTaskScheduler executor?
The Javadoc of #EnableScheduling is pretty exhaustive in that area.
You need to implement a SchedulingConfigurer to fine-tune which Executor needs to be used.
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
#Bean
public Executor taskScheduler() {
ThreadPoolTaskScheduler t = new ThreadPoolTaskScheduler();
t.setPoolSize(2);
t.setThreadNamePrefix("taskScheduler - ");
t.initialize();
return t;
}
}
Executor qualification with #Scheduled is not supported yet.
Refer -
https://jira.spring.io/browse/SPR-14218
Related
I have an async task executor.
How can I tell Spring to wait on application shutdown until all tasks are finished?
#Bean
public ThreadPoolExecutor singleExecutor() {
return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(10),
new ThreadPoolExecutor.DiscardPolicy());
}
#Service
class MyService {
#Async("singleExecutor")
public void runAsync() {
}
}
Solution
The org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor class (implements the org.springframework.core.task.TaskExecutor interface) supports the requested functionality by the the following methods:
setWaitForTasksToCompleteOnShutdown().
setAwaitTerminationSeconds().
Therefore, please, consider migrating the bean:
From: java.util.concurrent.ThreadPoolExecutor.
To: org.springframework.core.task.TaskExecutor.
«Migrated bean» example
#Bean
public TaskExecutor singleExecutor() {
final ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(1);
taskExecutor.setMaxPoolSize(1);
taskExecutor.setKeepAliveSeconds(0);
taskExecutor.setQueueCapacity(10);
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(300);
return taskExecutor;
}
ThreadPoolTaskExecutor class: Queue type
Please, see the Javadoc for the ThreadPoolTaskExecutor.createQueue() method on the default queue factory method behaviour:
protected BlockingQueue<Runnable> createQueue(int queueCapacity)
Create the BlockingQueue to use for the ThreadPoolExecutor.
A LinkedBlockingQueue instance will be created for a positive capacity value; a SynchronousQueue else.
It is possible to override the behaviour by using a class derived from the ThreadPoolTaskExecutor class with the overridden factory method.
For example:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
public final class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
#Override
protected BlockingQueue<Runnable> createQueue(final int queueCapacity) {
return new ArrayBlockingQueue<>(queueCapacity);
}
}
I've configuration that is implementing AsyncConfigurer as bellow:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(5);
executor.setCorePoolSize(5);
executor.setQueueCapacity(500);
executor.initialize();
return executor;
}
That new thread pool is working fine with that:
#Component
public class MessageJmsListener {
#Async
#EventListener
public void onApplicationEvent(CustomMessage messageJmsWrapper) {
log.info("Current thread: {}", Thread.currentThread().getName());
}
#Async
#EventListener
public void onApplicationEventSecond(SecondCustomMessage messageJmsWrapper) {
log.info("Second Listener thread: {} , Thread.currentThread().getName());
}
}
And I would like to achieve such an effect that for the first listener I give a separate bean (number of threads) and for the second. Is such a thing possible?
Thanks in advance!
Best Regards
It looks like that using qualifiers could help you.
Create two different executors and add different qualifiers for each.
Use the first one for the first listener with one one parameter set and the second one for the other one with different parameter set. See example in this thread.
Another approach in your case could be that you call the right executor by adding executor name in annotation where you are invoking it.
Example:
#Configuration
#EnableAsync
class ApplicationAsyncConfiguration {
#Bean(name = "maxThreadingExecutor")
public Executor maxThreadingExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(5);
executor.setCorePoolSize(5);
executor.setQueueCapacity(500);
executor.initialize();
return executor;
}
#Bean(name = "defaultExecutor")
public Executor defaultExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(2);
executor.setCorePoolSize(2);
executor.setQueueCapacity(500);
executor.initialize();
return executor;
}
}
#Component
public class MessageJmsListener {
#Async("maxThreadingExecutor")
#EventListener
public void onApplicationEvent(CustomMessage messageJmsWrapper) {
log.info("Current thread: {}", Thread.currentThread().getName());
}
#Async("defaultExecutor")
#EventListener
public void onApplicationEventSecond(SecondCustomMessage messageJmsWrapper) {
log.info("Second Listener thread: {}", Thread.currentThread().getName());
}
}
See more in this answer, might be helpful.
I have read many questions and answers about using #Scheduled with #Async in Spring but no one resolves my problem and my asynchronous method still runs single-threaded. So here is my Configuration class:
#EnableScheduling
#EnableAsync
#Configuration
#RequiredArgsConstructor
public class SchedulerConfiguration {
private final ThreadPoolProperties threadPoolProperties;
#Bean
public TaskExecutor commonTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(threadPoolProperties.getCorePoolSize()); // 10
taskExecutor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize()); // 20
taskExecutor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); // 5
taskExecutor.setThreadNamePrefix("TEST");
taskExecutor.initialize();
return taskExecutor;
}
}
Then we have a bean with the #Scheduled method:
#Component
#RequiredArgsConstructor
public class ScheduledTask {
private final ConfirmReservationTask confirmReservationTask;
#Scheduled(cron = "${booking.scheduler.confirmReservationsCron}")
public void process() {
confirmReservationTask.confirmReservations();
}
}
And finally, another bean (to avoid self-injection and proxy problems with asynchronous processing) with #Async method:
#Log4j2
#Component
#RequiredArgsConstructor
public class ConfirmReservationTask {
private final ReservationService reservationService;
#Async("commonTaskExecutor")
public void confirmReservations() {
...
}
}
unfortunately, this solution works in only one thread, however, the method uses the correct ThreadExecutor. How to solve it?
I have a Spring #Configuration class as follows:
#Configuration
public class ExecutorServiceConfiguration {
#Bean
public BlockingQueue<Runnable> queue() {
return ArrayBlockingQueue<>(1000);
}
#Bean
public ExecutorService executor(BlockingQueue<Runnable> queue) {
return ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue);
}
#PreDestroy
public void shutdownExecutor() {
// no executor instance
}
}
I would also like to specify a #PreDestroy method which shuts down the ExecutorService. However, the #PreDestroy method cannot have any arguments which is why I'm not able to pass the executor bean to this method in order to shut it. Specifying destroy method in #Bean(destroyMethod = "...") does not work either. It allows me to specify existing shutdown or shutdownNow, but not the custom method which I intend to use.
I know I could instantiate the queue and executor directly and not as Spring beans, but I'd rather do it this way.
I love defining classes inline:
#Bean(destroyMethod = "myCustomShutdown")
public ExecutorService executor(BlockingQueue<Runnable> queue) {
return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue) {
public void myCustomShutdown() {
...
}
};
}
Use the ThreadPoolTaskExecutor which does all that by default.
#Configuration
public class ExecutorServiceConfiguration {
#Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor() {
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
return new ArrayBlockingQueue<>(queueCapacity);
}
};
taskExecutor.setCorePoolSize(1);
taskExecutor.setMaxPoolSize(1);
taskExecutor.setKeepAliveSeconds(0);
taskExecutor.setQueueCapacity(1000);
return taskExecutor;
}
}
This will configure the ThreadPoolExecutor and shutdown when the application stops.
If you don't need the ArrayBlockingQueue but can live with the default LinkedBlockingQueue and only need to specify the queue capacity you can remove the override createQueue method.
Is it possible to inject the TaskScheduler instance created by Spring?
I would like to schedule tasks programatically and for that, I guess I need to access the TaskScheduler but for some reason, it's not found by Spring for autowiring.
#Configuration
#EnableScheduling
public class MySpringConfig {
}
#Component
public class MyClass implements InitializingBean {
#Autowired
private TaskScheduler taskScheduler;
#Override
public void afterPropertiesSet() throws Exception {
...
}
}
Any idea?
Thanks!
#Configuration
#EnableScheduling
public class MySpringConfig {
#Bean
public TaskScheduler taskScheduler() {
//org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
return new ThreadPoolTaskScheduler();
}
}
You can choose which ever implementation you like. ThreadPoolTaskScheduler is the simpler one as mentioned in this link.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-task-scheduler-implementations