Spring Boot Async Programming - java

I'm new in software. I'm working to understand async programming in Spring Boot. As seen above, I set thread pool size 2. When I requested same url three times one after another. My two requests are working asynchronously. Third one is waiting. This is ok. But when I don't use the asynchronous feature (neither #async annotation nor threadpool), it still performs transactions asynchronously, as before. So I'm confused. Spring Boot rest controller behaves asynchronously by default? Why we use #async in Spring Boot? Or do I misunderstand that?
#Service
public class TenantService {
#Autowired
private TenantRepository tenantRepository;
#Async("threadPoolTaskExecutor")
public Future<List<Tenant>> getAllTenants() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
List<Tenant> allTenants = tenantRepository.findAll();
Thread.sleep(5000);
return new AsyncResult<>(allTenants);
} catch (InterruptedException e) {
//
}
return null;
}
}
#Configuration
#EnableAsync
public class AsyncConfig {
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
return executor;
}
#Bean(name = "threadPoolTaskExecutor2")
public Executor threadPoolTaskExecutor2() {
return new ThreadPoolTaskExecutor();
}
}

I'm assuming you are using the default embedded Tomcat from Spring Boot. If that's the case, then you are not misunderstanding. Tomcat will indeed work asynchronously by default, meaning it will start a new thread for every request (see this for on that).
The #Async annotation does not aim to replace the functionality that Tomcat provides in this case. Instead, that annotation allows executing any method of a bean in a separate thread. For your particular use case, it might be enough to let Tomcat start a new thread for every request, but sometimes you might want to parallelize work further.
An example on when you would probably want to use both is when a request must trigger some heavy computation, but the response does not depend on it. By using the #Async annotation, you can start the heavy computation on another thread, and let the request finish sooner (effectively allowing the server to handle other requests while the heavy computation runs independently on another thread).

Related

How to select to use a specific task executor in a method in springboot java?

I have an application that uses CompletableFuture to process data from a stream async. The demo showcasing my async implementation is as follows:
#Async
#Transactional(readOnly = true)
public void beginProcessing() {
try(Stream<String> st = myJpa.getMyStream()) { // use spring jpa to get a stream of data from db
CompletableFuture.allOf(st.map(i -> CompletableFuture.supplyAsync(() ->
myMethod(i)))
.toArray(CompletableFuture[]::new)).join();
}
}
#Async
private CompletableFuture<Void> myMethod(String i) {
// logic goes here
}
And it works fine. However, at the moment the CompletableFuture uses some default thread pool to do its job. I would like to use a custom defined taskExecutor instead. This can be achieved by supplying a name of the taskExecutor as a 2nd argument of supplyAsync(...) method. I have done it with ForkJoin thread pool before, so I am positive that it works.
Now, I want to make it work with taskExecutor, so I have added a new bean to my config class as below (as well as another one which I will use elsewhere):
#Configuration
public class MyConfigClass {
#Bean
public TaskExecutor myNewExecutor() {
RejectedExecutionHandler re = new ThreadPoolExecutor.CallerRunsPolicy();
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(0);
executor.setThreadNamePrefix("myNewExecutor-");
executor.setRejectedExecutionHandler(re);
return executor;
}
#Bean
public TaskExecutor someOtherExecutor() { // would be used elsewhere
RejectedExecutionHandler re = new ThreadPoolExecutor.CallerRunsPolicy();
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(0);
executor.setThreadNamePrefix("someOtherExecutor-");
executor.setRejectedExecutionHandler(re);
return executor;
}
}
And then I autowired TaskExecutor into my class and added the 2nd arg. So the code looks like below:
#Autowired
private TaskExecutor myNewExecutor;
#Async
#Transactional(readOnly = true)
public void beginProcessing() {
try(Stream<String> st = myJpa.getMyStream()) { // use spring jpa to get a stream of data from db
CompletableFuture.allOf(st.map(i -> CompletableFuture.supplyAsync(() ->
myMethod(i),myNewExecutor))
.toArray(CompletableFuture[]::new)).join();
}
}
#Async
private CompletableFuture<Void> myMethod(String i) {
// logic goes here
}
However, that does not work since we have multiple beans of type TaskExecutor, so I get the following exception
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available: expected single matching bean but found 3: myNewExecutor, someOtherExecutor, taskScheduler
Ok, so I thought I would be able to solve it by using #Qualifier annotation. However, it didn't work for me - the exception is still being thrown (I used said annotation under the #Bean annotaiton in a config class and then under the #Autowired annotation in my class where logic is.).
I know that you can make a method use a custom thread pool by giving each bean a name and having the corresponding name being passed as an arg to #Async annotation. So, I guess I could rework my code to be a simple for loop that calls mytMethod(...) with method's async annotation being replaced with #Async("myNewExecutor"). That would probably work but I would like to preserve CompletableFuture if I can, so wonder if anyone can identify what am I missing that results in the error mentioned above?
I feel like I am missing something trivial to make it work but I just cannot see it.
So ... I figured it out. It was indeed a trivial thing that I somehow missed (embarrassingly so).
By specifying which thread pool to use in my logic, I made sure to effectively tell #Async above myMethod(...) which of 3 available beans to use. But I forgot that I have one more #Async above beginProcessing() method. So naturally it was confused with these changes and was throwing the exception I mentioned. By specifying which thread pool it needs to use (using bean name trick I mentioned I know), the code works like a charm.

ScheduledExecutorService inside a Spring Bean, not working after a couple of executions

I am trying to schedule a task inside a Spring #Bean which will update the property of the instance returning from Bean.
I am able to run this code, and the executor works fine a couple of times, but after that, it suddenly stops loading.
What exactly is the problem here? Is there a better way to work this out??
#Bean(name="service")
public Service getService(){
Service service = new Service();
ScheduledExecutorService serviceLoader = Executors.newScheduledThreadPool(1);
serviceLoader.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
return service;
}
The lifecycle of serviceLoader looks weird - it gets initialized right during the method or service, then schedules some work and then service gets returned. What happens to the reference to this pool? when the shutdown can be called?
In addition, the first iteration runs immediately, and this happens when the application context is not ready yet, this can lead to unpredictable results depending on the actual code that runs during the iteration.
I can't say for sure what happens based on this code snippet, but here are some possible solutions:
Use #Scheduled annotation, running scheduled tasks is a bulit-in spring feature. There are a lot of tutorials, here is one of them
If you absolutely have to use the thread pool, I suggest the following configuration:
#Configuration
public class MyConfiguration {
#Bean
public Service service() {
return new Service();
}
#Bean(destroyMethod="shutdownNow") // or shutdown - now spring will close the pool when the app context gets closed
#Qualifier("serviceLoaderPool")
public ScheduledExecutorService serviceLoader() {
return Executors.newScheduledThreadPool(1);
}
#EventListener
public void onAppContextStarted(ApplicationReadyEvent evt) {
ScheduledExecutorService loader =
(ScheduledExecutorService)evt.getApplicationContext().getBean("serviceLoaderPool");
Service service = evt.getApplicationContext.getBean(Service.class);
loader.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
}
}
With this approach you can be sure that the service will start refreshing when the application context is ready.
The lifecycle of the executor service is well-defined as well, spring manages it as a regular singleton bean, so it won't be GC'ed as long as the application context is up-and-running.
The presence of destroy method guarantees graceful shutdown (again, spring will call it for you).

How to use multiple threadPoolExecutor for Async Spring

I am using Spring #Async on two classes. Both are ultimately implementing an interface. I am creating two separate ThreadPoolTaskExecutor so each class has its own ThreadPool to work off of. However due to I think something with proxy and how Spring implements Async classes, I have to put the #Async annotation on the base interface. Because of this, both classes end up using the same ThreadPoolTaskExecutor.
Is it possible to tell Spring that for this Bean (in this case I am calling the classes that implement that interface a Service), use this ThreadPoolTaskExecutor.
By default when specifying #Async on a method, the executor that will be used is the one supplied to the 'annotation-driven' element as described here.
However, the value attribute of the #Async annotation can be used when needing to indicate that an executor other than the default should be used when executing a given method.
#Async("otherExecutor")
void doSomething(String s) {
// this will be executed asynchronously by "otherExecutor"
}
In this case, "otherExecutor" may be the name of any Executor bean in the Spring container, or may be the name of a qualifier associated with any Executor, e.g. as specified with the element or Spring’s #Qualifier annotation
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
And probably you need to specify the otherExecutor bean in you app with the pool settings you wish.
#Bean
public TaskExecutor otherExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
return executor;
}

spring scheduler not running if a job not finished

I'm trying to make a lib for my spring applications. It has a scheduled job, it is autoconfigured and working as included Maven dependency in most cases.
I have a webapp which basically just flood requests to other webapps (some basic load-testing and fail-detection). The requester implementation is fully async (it has a manually configured async executor too). The web app has a periodic job too, but it doesn't finish reliably its job within the 2 minutes timeframe. It still fine. BUT.
When I started to use my firstly described lib on the secondly described server the lib starts working unreliable. It's not triggered every 2 minutes anymore. I don't have enough spring knowledge to find out why.
My best bet is the servers flood method starts a lot of async tasks, and the scheduler start these tasks, too and these requests are going to the same message queue.
Is there any method to separate my libs scheduled tasks from other servers scheduled tasks and make them running reliable every 2 minutes?
So my research is interesting... It seems to be, only configuring an async executor will force the scheduler to use that too. But if you implements schedulerConfigurer too, you will get another thread pool dedicated to scheduled tasks only.
So my implementation is something like this for separate the 2 threadpool.
#SpringBootApplication
#EnableAsync
#EnableScheduling
#ComponentScan
public class WebService extends AsyncConfigurerSupport implements SchedulingConfigurer {
public static void main(String[] args) {
System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "8888");
System.setProperty("spring.config.name", "web-server");
SpringApplication.run(WebService.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(4);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("tester-");
executor.initialize();
return executor;
}
#Bean(destroyMethod = "shutdown", name = "scheduledExecutor")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
#Autowired
#Qualifier(value="scheduledExecutor")
Executor scheduledExecutor;
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(scheduledExecutor);
}
Still not clear enough if I could create a separated thread-pool for my lib or not, but its good enough for now.

Create a threadpool by ThreadPoolTaskExecutor or ThreadPoolExecutorFactoryBean?

I'd like to create an executor service that I can use as follows:
#Asyn(value = "asyncService")
public void task() {
//...
}
When should the #Bean be created using ThreadPoolTaskExecutor or ThreadPoolExecutorFactoryBean?
#Bean
public ExecutorService getAsyncService() {
//when to favor ThreadPoolTaskExecutor over ThreadPoolExecutorFactoryBean
}
Are there any cases where one should be favored over the other?
Favor direct injection of the TaskExecutor unless running under an app server, mainframe, or other environment where you need special handling of threads. Like the docs say, it's easy to get confused on which class you're using otherwise.

Categories

Resources