I'm trying to convert XML configuration for using Spring's tasks framework into purely code configuration. I'm able to reproduce the functionality but whenever I shut down the war on the Tomcat server the task scheduler lives on, it hangs (it doesn't hang with XML configuration). I've debugged to inspect the instances of scheduler and executor but I'm not seeing a difference so I'm not sure what could be causing it to hang.
Here is the XML configuration that works:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:executor id="com.work.gwx.pix.executor"
pool-size="${pix.job.executor.pool.size:1-40}"
queue-capacity="${pix.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" />
<bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" />
</beans>
Here is the code configuration:
#EnableAsync
#EnableScheduling
#Configuration
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer {
#Value("${pix.job.executor.max.pool.size:1}")
private int executorMaxPoolSize;
#Value("${pix.job.executor.queue.capacity:0}")
private int executorQueueCapacity;
#Value("${pix.job.scheduler.pool.size:4}")
private int schedulerPoolSize;
#Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
#Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(new ThreadPoolTaskExecutor());
executor.initialize();
return executor;
}
#Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(pixTaskScheduler());
}
#Override
public Executor getAsyncExecutor() {
return pixExecutor();
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
When I use setExecuteExistingDelayedTasksAfterShutdownPolicy(false) in code configuration it does shut down but I'm worried that might have adverse effects as that is set to true when done via XML configuration. Also, I should note, the QueueProcessor class is doing the work I want and I don't mind if delayed executions get cancelled -- I just don't want currently executing threads to be abruptly cancelled.
This is the message I get when it hangs:
SEVERE: The web application [/pix-queue-processor] appears to have
started a thread named [ThreadPoolTaskExecutor-1] but has failed to
stop it. This is very likely to create a memory leak.
Any ideas on what might be causing the hanging? Or, would using that commented out method let me do what I want (won't kill a running task but will cancel delayed tasks)?
Your Java based configuration isn't really a representation of the the XML configuration. There are at least 2 things that are different.
Your TaskExecutor has another TaskExecutor wired as a ThreadFactory this isn't the case in XML and also starts another TaskExecutor.
Your TaskScheduler uses a new TaskExecutor whereas the xml configuration use the one configured.
The have your task finished on shutdown you can set the waitForTasksToCompleteOnShutdown property on the TaskExecutor to true then any pending tasks will be completed and no new tasks will be accepted.
Also the call to initialize shouldn't be needed as the afterPropertiesSet method will be called by Spring which in turn calls initialize.
The following 2 bean definitions are more in line with the XML configuration (and you now have a single TaskExecutor instead of 3 and it will first finish tasks before shutdown.
#Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
#Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
Related
I've implemented asynchronous execution for a method in my application using Spring Boot #Async. I'm having a custom thread pool with 20 thread. In a for loop calling the async method for 30 times.
Each individual request is executing asynchronously but when i made two different requests at the same time to my API from browser, first request is executing and then second. Not both requests executing the same method parallely.
I thought when first request reach the app, it's started executing the async method and since it's being executing for 30 times and my pool is having 20 threads, all threads are busy in executing first request. So even second request came for execution also since the pool of threads busy, the other request is waiting till a thread becomes free in the pool.
Can we have separate thread pool for each individual request. or any way that we can make execution of each request separate independent of other request processing.
Here is my code sample.
#SpringBootApplication
#EnableAsync
public class AppBootStrap
{
public static void main(String[] args)
{
SpringApplication.run(AppBootStrap.class, args);
}
#Bean
public AsyncTaskService asyncTaskService() {
return new AsyncTaskService();
}
#Bean(name="customExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(10);
poolExecutor.setMaxPoolSize(20);
poolExecutor.setThreadNamePrefix("customPoolExecutor");
poolExecutor.initialize();
return poolExecutor;
}
}
**Controller Class:**
#RestController
public class TaskController
{
#Autowired
private TaskService taskService;
#RequestMapping("/performAction")
public void performAction() {
taskService.performAction();
}
}
**Service class**
#Service
public class TaskService
{
#Autowired
private AsyncTaskService asyncTaskService;
public void performAction()
{
for(int i = 0; i < 30; i++) {
asyncTaskService.greetings(i);
}
}
}
**Async Method Class**
public class AsyncTaskService
{
#Async
public void greetings(Integer i)
{
try
{
Thread.sleep(500 * (i + 10));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Welcome to Async Service: " + i);
}
}
#Bean(name = "apiTaskExecutor")
public ThreadPoolTaskExecutor apiTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(50);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
#Bean(name = "lruTaskExecutor")
public ThreadPoolTaskExecutor lruTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(500);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
The Way to do this is to create two Thread different Thread Pools using Different Qualifier names. (As shown above)
#Autowired
#Qualifier("apiTaskExecutor")
private ThreadPoolTaskExecutor apiTaskExecutor;
Then autowire the required pool using the qualifier you have given . You can also use the #Async annotation instead of autowiring . I prefer this way.
If I am not wrong this way of having different thread pools for different Tasks is known as bulkhead pattern.
I think the problem is that the customExecutor bean is a singleton. This means that when the second request tries to use this bean it finds all the threads of the thred pool busy. You can try to make the customExecutor bean non-singleton by using the #Scope("prototype") annotation which will cause a new one to be instantiated whenever a bean of this type is requested.
I have a class which I want to run jobs from asynchronously. To do this I have the following code:
#Resource
private SimpleJobLauncher jobLauncher;
#PostConstruct
public void initLauncher(){
jobLauncher.setTaskExecutor(taskExecutor());
}
However, there is a situation where I need to do this synchronously. So, what I have done is added the following variable:
#Resource
private SimpleJobLauncher synchronousJobLauncher;
Which I hoped wouldn't have the taskExecutor on it making it synchronous. I then pass the synchronousJobLauncher to the places where I want to do things synchronously. However, using the synchronousJobLauncher gives me the same error as when I use the asynchronous one which leads me to believe that you cannot autowire the same variable twice like I am trying to do. If I do not do the #PostConstruct part of the code, the synchronous part works like I expect but not the asynchronous part, even though they use, what I think are, different job launchers.
Any ideas? I have tried using the #Resource annotation instead of #Autowired.
I haven't used SimpleJobLaunchers, but normally, in Spring I always used the #Async annotation, which make asynchronous execution quite simple. All you have to do is add this annotation, #EnableAsync in any configuration file, just like the one below.
#Configuration
#EnableAsync
public class MvcConfig extends WebMvcConfigurerAdapter { ... }
Now, is all about adding the #Async to any method that will run asynchronously.
#Component
class AsyncTask {
#Async
public Future<String> run() throws InterruptedException {
return new AsyncResult<String>("return value");
}
}
And if you want to wait for the result, you can do the following.
public void callAsyncTask() {
try {
Future<String> future = asyncTask.run();
// Do some other things while the async task is running.
// future.get() will block the function and wait for the result.
String asyncResult = future.get();
} catch(InterruptedException e) {
e.printStackTrace();
// Do something else.
}
}
Hope this helps. I know is not directly what you were asking for, but maybe this solution can facilitate your problem.
You can create two job launchers (one synchronous and one asynchronous) then inject the one you want using a qualifier. By default, the SimpleJobLauncher uses a synchronous task executor, so you need to configure a task executor only for the asynchronous one. Here is an example:
#Bean
public SimpleJobLauncher synchronousJobLauncher() {
return new SimpleJobLauncher();
}
#Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
#Bean
public SimpleJobLauncher asynchronousJobLauncher() {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setTaskExecutor(threadPoolTaskExecutor());
return jobLauncher;
}
Then, inject the job launcher you want with a #Qualifier("synchronousJobLauncher") or #Qualifier("asynchronousJobLauncher") according to your needs.
Hope this helps.
Spring framework has an interface AsyncConfigurer (and AsyncConfigurerSupport) for configuring everything necessary for having a thread pool executor and being able to run methods asynchronously (with #Async).
But usually, it's not a good practice to share the same thread pool among different functionalities, so usually I qualified them with a name, and I specify that name in Async annotation for it to use one specific thread pool.
Thing is, I would like to configure them through this convenient interface AsyncConfigurer and not loosing qualification, but I'm not able to.
Trying this:
#Configuration
#EnableAsync
public class PusherAsyncConfigurerSupport extends AsyncConfigurerSupport {
#Autowired
ExecutorConfig config;
#Override
#Qualifier(value = "executorOne")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
...
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
That thread pool is still not recognized when put in an Async annotation.
So, what is it needed for configuring several thread pools this way? Or isn't it the way for that at all?
mark with #Bean annotation
#Bean
#Qualifier(value = "executorOne")
public Executor getAsyncExecutor() {
//..
return executor;
}
I'm starting spring-batch jobs using JobLauncher.run().
Question: how can I threadpool those invocations? So that eg a maximum of 4 job threads may be running concurrently, and any further jobs are just queued?
#Autowired
private JobRegistry registry;
#Autowired
private JobLauncher launcher;
Job job = registry.getJob("jobname");
launcher.run(job, params); //immediately starts the job
You can set ThreadPoolTaskExecutor as the task executor used by the SimpleJobLauncher (the class that actually launches the jobs). This executor has some properties you can set, especially maxPoolSize.
public JobLauncher createJobLauncher() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(4);
taskExecutor.setMaxPoolSize(4);
taskExecutor.afterPropertiesSet();
SimpleJobLauncher launcher = (SimpleJobLauncher) super.createJobLauncher();
launcher.setTaskExecutor(taskExecutor);
return launcher;
}
Please take a look at the docs.
Possibly a duplicate of Spring Batch Multiple Threads and How to set up multi-threading in Spring Batch?.
Update:
I use the following code to start a batch job asynchronously. But I don't know how to limit the maximum number of executions as you mentioned.
TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
taskExecutor.execute(new Runnable() {
public void run() {
try {
jobLauncher.run(importJob, jobParametersBuilder.toJobParameters());
} catch (Exception e){
e.printStackTrace();
}
}
});
I am trying to convert the following Spring task xml configuration to a purely code/annotation based version:
<task:executor id="xyz.executor"
pool-size="${xyz.job.executor.pool.size:1-40}"
queue-capacity="${xyz.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="xyz.scheduler" pool size="${xyz.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="xyz.executor" scheduler="xyz.scheduler" />
<bean id='xyzProcessor' class="xyz.queueing.QueueProcessor" />
<task:scheduled-tasks scheduler="xyz.scheduler" >
<task:scheduled ref="partitioner" method="createPartitions" cron="${xyz.job.partitioner.interval:0 0 3 * * *}" />
</task:scheduled-tasks>
Per the Spring spec, 28.4.1 (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html), they say that to go from XML like this:
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
to code configuration is as simply as enabling either #EnableScheduling and/or #EnableAsync.
However, I don't see anywhere I can actually instantiate the scheduler. The javadoc for #EnableScheduling (http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html) shows how I can get plug in my own created Executor, though I'm not exactly sure what class it should be (I still want to be able to control the pool size, queue capacity, and rejection policy). It also shows how I can schedule my createPartitions method using the configureTasks override. However, I would like to be able to name my scheduler (so I can identify its threads) and control its pool size.
So, I wish to know these things:
1) What class can I use to set the executor fields that the XML has?
2) Is there a way to create a scheduler instance that I can control the name and pool size of?
Check out the types AsyncConfigurer, AsyncConfigurerSupport, and SchedulingConfigurer. They are helper types you can use to enhance your #Configuration class with async/scheduling configurations.
Across all of them, and the javadoc of #EnabledAsync, you'll find all the setup methods you need to setup your async/scheduling #Configuration class.
The example given equates
#Configuration
#EnableAsync
public class AppConfig implements AsyncConfigurer {
#Bean
public MyAsyncBean asyncBean() {
return new MyAsyncBean();
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
with
<beans>
<task:annotation-driven executor="myExecutor" exception-handler="exceptionHandler"/>
<task:executor id="myExecutor" pool-size="7-42" queue-capacity="11"/>
<bean id="asyncBean" class="com.foo.MyAsyncBean"/>
<bean id="exceptionHandler" class="com.foo.MyAsyncUncaughtExceptionHandler"/>
</beans>
SchedulingConfigurer has a similar setup for task:scheduler.
If you want more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces.
As belows,
Please notice the pools also,
#Configuration
#EnableScheduling
public class CronConfig implements SchedulingConfigurer{
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
And for the Asyncs,
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
Note that #EnableAsync and #EnableScheduling has to be there for this to work.