Custom ThreadPoolTaskExecutor with Spring Boot Async - java

I have a Spring Boot application which is responsible for answering requests via REST. I also push metrics about my application call. Since this is a separate task and I have to response users immediately, I want to make that metrics publishing asynchronously. So I've used that:
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("MyApp-");
executor.initialize();
return executor;
However, this one uses SimpleAsyncTaskExecutor and does not reuse any threads.
1) How can I use ConcurrentTaskExecutor instead of SimpleAsyncTaskExecutor?
2) Which implementation could best fit for my needs?

To make your custom Executor work, make sure it's registered as a Bean, and reference it on the method annotated with #Async:
#Bean(name = "transcodingPoolTaskExecutor")
public Executor transcodingPoolTaskExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("transcoder-");
executor.initialize();
return executor;
}
And in the #Service which is holding the method:
#Async("transcodingPoolTaskExecutor")
public void transcodeVideo(UUID fileId) {
mediaFileService.transcodeVideo(fileId);
}

You can also redefine the default executor by creating a Configuration class which implements AsyncConfigurer. Something like this:
#EnableAsync
#Configuration
public class AsyncConfig implements AsyncConfigurer {
#Value("${async.executor.corePoolSize:20}")
private int corePoolSize;
#Value("${async.executor.maxPoolSize:100}")
private int maxPoolSize;
#Value("${async.executor.queueCapacity:50}")
private int queueCapacity;
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("Async Executor -");
executor.initialize();
return executor;
}
}
In this case you wouldn't need to specify the executor name in #Async annotation. Spring will take executor, which you defined in AsyncConfig.
It's very similar to the solution provided by yglodt, but in this case you don't need to specify the name of executor in every #Async annotation, so it removes potential misspelling in the executor name.

Related

How to delay application shutdown while running #Async tasks?

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);
}
}

How to specify a thread pool for a specific process

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.

How To Shut Down Specific Task(Process) of ThreadPoolTaskExecutor In Spring Boot?

Hello everyone
I want to terminate or shut-down a specific task in ThreadPoolTaskExecutor
e.g.
i want to set a unique id or name for each task i will queue then shut it down using its id or name which i added to this task
that is because i have users and my application use case force me to specify tasks for each user but sometimes i want to shut down specific task for specific user
for example
user.setTaskId('john-deo-1521');
user.setTaskId('john-deo-1522');
and for shutting down
taskExecutor.shutDownTaskById('john-deo-1521');
and this is my main configuration for ThreadPoolTaskExecutor
#Configuration
#EnableAsync
public class ServiceExecutorConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(30);
taskExecutor.setMaxPoolSize(40);
taskExecutor.setQueueCapacity(10);
taskExecutor.initialize();
return taskExecutor;
}
}

Shutdown #Bean ExecutorService using #PreDestroy

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.

Proper way to start new thread from service layer using spring

I have a method that will be rarely called. This method collect garbage in db. I don't want to make user to wait for server response so i decided to call this method from new thread from my service layer. i'm using Spring.
Service class:
#Service
#Transactional
public class UploadService {
#Resource(name = "UploadDAO")
private UploadDao uploadDao;
Method that i don't want to wait for
public void collectBlobGarbage(){
Thread th = new Thread(new Runnable() {
#Override
public void run() {
uploadDao.collectBlobGarbage();
}
});
th.start();
}
Is it a good way to do like this?
If you have Spring on your classpath you might as well use #Async
#Async
public CompletableFuture<Void> collectBlobGarbage() throws InterruptedException {
CompletableFuture.completeFuture(uploadDao.collectBlobGarbage());
}
On your main class you need to use #EnableAsync like:
#SpringBootApplication
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
And you need an executor bean:
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Stackoverflow-");
executor.initialize();
return executor;
}
I think the provided solution can potentially cause a lot of threads on you server.
As an alternative, you can consider using Executors.newSingleThreadExecutor in such a way that you will get an executor service that is limited only to one thread—so you will never create more than one thread—and that is what you need.
Also as you are using Spring, consider configuring a SingleThreadExecutor instantiation as a separate bean—in such a way that you will be able to change the implementation of ExecutorService in the future.

Categories

Resources