ThreadPoolTaskExecutor spawning unwanted threads - java

I have two Async methods that are configured to use the same TaskExecutor.
#Async("myExecutor")
public void foo() {
system.out.println("foo from: " + Thread.currentThread().getName());
}
#Async // this should use the primary defaultExecutor
// try to bombard the single thread pool with bunch of requests
public void generateFoo() {
while(true) {
system.out.println("generateBar from: " + Thread.currentThread().getName());
this.foo();
}
}
I want the underlining threadpool of myExecutor to have a coresize and maxsize of 1 and queue incoming requests for the thread. I.e only one thread executing foo() runs at a time and all other calls to foo() waits for their turn. In my Spring configuration class, I have
#Configuration
#ComponentScan(basePackages = { "com.test" })
#EnableAsync
#EnableScheduling
public class FooBarConfig {
#Bean
#Primary
#Qualifier("defaultExecutor")
public TaskExecutor defaultExecutor() {
return new ThreadPoolTaskExecutor();
}
#Bean
#Qualifier("myExecutor")
public TaskExecutor myExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setQueueCapacity(Integer.MAX_VALUE);
return executor;
}
}
However, I'm seeing that foo() isn't always being executed from the same thread. If I call foo() via a #Scheduled task from another thread, it runs on "myExecutor-1" as expected. But if foo() is called via generateFoo(), it seems to be running in whatever generateFoo() runs from, ie:
foo from: defaultExecutor-1
foo from: myExecutor-1
foo from: defaultExecutor-1
foo from: defaultExecutor-1
foo from: defaultExecutor-1
If I get rid of generateFoo()'s #Async, foo() still runs on whatever thread generateFoo() is running on.
Am I using the wrong TaskExecutor for what I'm looking for or configuring it incorrectly?
edit
As state in my original post, not making generateFoo() an async method doesn't seem to do the trick, as someone suggested.

Related

How to call multiple functions of different Spring beans in async

I am new to Async in Spring boot.
I have a bean A as follows:
class A {
private final B b;
private final C c;
...
int x = b.f();
c.g(x);
...
}
Here I would like to call both f() and g() in async. I have got some ideas from different articles regarding how to make #Async work. But, being a newbie, I cannot understand how would I call g() with the return value of f() in async.
It's pretty straight forward ,Add #EnableAsync annotation to a configuration class or to the main application class then add the #Async annotation to the method that you want to be executed asynchronously on a separate thread. Springboot will setup a thread pool and using proxy will automatically start a new thread to handle the method call. But if you want to return something from the method then use Future. You can also control which thread pool to use by creating a thread pool executor bean like below and specifying it in the #Async annotation.
#Configuration
#EnableAsync
class GeneralConfiguration {
#Bean(name = "asyncTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setThreadNamePrefix("ScheduledTaskThread-");
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
class B {
#Async("asyncTaskExecutor") //ask spring to use your thread pool for this async task.
public Future<Integer> f() {
//Do something
return new AsyncResult<Integer>(1);
}
}
class C {
#Async
public void g() {
//Do something
}
}
From your comments, in order to wait for thee result of method f of class B to be provided as input to the method g of class C then use CompletableFuture like :
class B {
#Async("asyncTaskExecutor") //ask spring to use your thread pool for this async task.
public CompletableFuture<Integer> f() {
//Do something
return CompletableFuture.completedFuture(1);
}
}
Then after while calling the method do something like :
...
CompletableFuture<Integer> result = b.f();
CompletableFuture.allOf(result).join(); //add other futures if you want to wait for other calls to complete.
c.g(result.get());
...
Obviously there are other optimized way to use Completable Future . But it depends on how you want to use this in your code. I suggest going through the completable future docs and finding out which suits your use case best.

How to get details of Spring Boot #Async method's rejected task?

In my application I'm using an #Async method which is calling a rest service and based on the rest service result I'm updating the MyJob status in DB.
#Async("thatOneTaskExecutor")
public void myAsyncTask(MyJob job) {
// get job details from the job and call rest service
// update the job with the result from rest service and save updated MyJob to DB
}
I'm using Spring's ThreadPoolTaskExucutor, Below is a snap from my AsyncConfiguration class where I declared this task executor.
private ThreadPoolTaskExecutor createExecutor(String name, int core, int max, int queue) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(core);
executor.setMaxPoolSize(max);
executor.setQueueCapacity(queue);
executor.setThreadNamePrefix(name);
executor.setTaskDecorator(new MdcAwareTaskDecorator());
executor.initialize();
return executor;
}
#Bean(name = "thatOneTaskExecutor")
public Executor taskExecutor() {
String prefix = "thatOneTask-";
String corePoolSize = 12;
String maxPoolSize = 20;
String queueSize = 1000;
ThreadPoolTaskExecutor executor = createExecutor(prefix, corePoolSize, maxPoolSize, queueSize);
executor.setRejectedExecutionHandler(new RejectedExecutionHandlerImpl());
return executor;
}
As you can see I had configured a RejectedExecutionHandler for my Executor.
According to Spring documentation when queue is full this method will be called.
* Method that may be invoked by a {#link ThreadPoolExecutor} when
* {#link ThreadPoolExecutor#execute execute} cannot accept a
* task. This may occur when no more threads or queue slots are
* available because their bounds would be exceeded, or upon
* shutdown of the Executor.
public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
#Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.error("Task Rejected because of max queue size");
// How to get info about that particular job, for which Task executor rejected this task??
}
}
Rejected execution handler is working fine for me, now inside this rejectedExecutorion method, I want to access the MyJob(parameter of my async method) for which the async task is rejected. I want to update that particular rejected job with a status so that I can later run a corn and process those rejected jobs. Inside this rejectedExecution method I only have Runnable and ThreadPoolExucutor, how can I extract/get info about MyJob here?
My application's Spring boot version is 2.2.2.RELEASE
You could consider using the TaskExecutor directly instead of the #Async annotation by implementing the Runnable interface for MyJob Class and perform the required async operation inside the run() method.
The Runnable r could be cast back to MyJob Object in the rejectedExecution method of the handler and hence you could retrieve information of your job from there.
public class Myjob implements Runnable{
.......
#Override
public void run(){
//get job details from the job and call rest service
//update the job with the result from rest service and save updated MyJob to DB
}
}
#Autowired
TaskExecutor taskExecutor;
public void myAsyncTask(MyJob job) {
taskExecutor.execute(job)
}
public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
#Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.error("Task Rejected because of max queue size");
if(r.getClass()==MyJob.class)
{
MyJob failedJob=(MyJob)r; //Job info
}
}
}

Java Spring boot async method isn't being called occasionally

I have a service with a method annotated with #Async as below:
#Service("AsyncService")
public class AsyncService {
#Async
public void asyncPrint() {
logger.info("Inside asyncPrint");
}
}
The async method is called from another service like this:
#Service("CallerService")
public class CallerService {
#Autowired
private AsyncService asyncService;
public void caller() {
logger.info("Before asyncPrint");
asyncService.asyncPrint();
logger.info("After asyncPrint");
// Custom code
}
}
However, I'm seeing that sometimes the async method is not being called. I can see the before and after logs, but the async log is not printed.
Sample o/p:
//Logs from other services
Before asyncPrint
After asyncPrint
Inside asyncPrint
//Logs from other services
Before asyncPrint
After asyncPrint
Why could this be happening? Can async tasks be dropped if there is a backlog in the Executor? Also, is there a way for me to see how many of the total running threads are being used by the async? Or how else can I debug this?
Thanks.
The log doesn't mean your Async method isn't being called, it means the Executor hasn't called it yet. The #Async uses a ThreadPoolTaskExecutor by default with unlimited queue capacity. This means ALL your tasks will be queued until processing threads become available.
If you want to increase your processing Threads you can defined a custom ThreadPoolTaskExecutor bean as below.
#Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
Where you can play with corePoolSize and maxPoolSize according to your hardware specifications.

How to get the queue size of the executor in real time

Supposed i have this application.java
#SpringBootApplication
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(5000);
executor.setThreadNamePrefix("sm-async-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
}
My goal is to create an alert if the current real time queue size of the async executor is in 80% or nearly the limit. I think we can get the value from executor.getThreadPoolExecutor().getQueue().size();. Im currently stuck on how to achieve that
#Controller
public class QueueMonitorController {
#Autowired
private Executor executor;
#RequestMapping(value = "/queuesize", method = RequestMethod.GET)
public int queueSize() {
ThreadPoolExecutor tpe = (ThreadPoolExecutor)executor;
return tpe.getQueue().size();
}
}
If you can provide the bean as a ThreadPoolExecutor, then you don't even need the cast. The internal implementation of size() in LinkedBlockingQueue (which ThreadPoolExecutor uses) is AtomicInteger.get().
So there's no need to get creative and build your own mechanisms, it's all built-in. Based on Spring 4.2, but shouldn't depend on the version too much.
So the root goal is to monitor the queue, and send an alert when queue is 80% full. This should not go into your code which is responsible for making sure that your business logic works. You shouldn't make hacks there to account for lack of resources. If the idea is that you should throttle users when the queue is packed, there are far better ways to handle those.
Since the idea is to do "light monitoring", i.e. there's no attempt to handle a case when queue is 80% full, a polling solution would be lightweight enough. Considering that the executor can be easily injected to a separate Controller, it won't even mess up your "real" code.
As ThreadPoolTaskExecutor does not expose any API you can get the queue used by it. However, you are free to extend ThreadPoolTaskExecutor and create a CustomThreadPoolTaskExecutor override the createQueue.
public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor{
private BlockingQueue<Runnable> queue;
#Override
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
queue = super.createQueue(queueCapacity);
return queue;
}
public BlockingQueue<Runnable> getQueue(){
return queue;
}
}
Now you can create asyncExecutor like below :
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();
//set other properties
executor.initialize();
return executor;
}
Your CustomThreadPoolTaskExecutor executor has public method getQueue and you can use that to get the queue.
I don't know from where you have got ThreadPoolTaskExecutor class type of executor. But in java you can typecast to ThreadPoolExecutor and get queue and it's size as below:
ThreadPoolExecutor executorService = (ThreadPoolExecutor )Executors.newCachedThreadPool();
executorService.getQueue().size()
To do this in real-time as you're asking for is not so easy. You'll need to decorate the methods of BlockingQueue so that you can add code to execute immediately when the content of the queue changes.
You can then provide your queue to Spring's ThreadPoolTaskExecutor like this:
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {
#Override
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
// create and return your instance of blocking queue here
}
};

multi subscriber of a spring integration ExecutorChannel

In my application I configure some channels as follows:
#Bean
public MessageChannel eventFilterChannel() {
return new ExecutorChannel(asyncConfiguration.getAsyncExecutor());
}
#Bean
public MessageChannel processEventChannel() {
return new ExecutorChannel(asyncConfiguration.getAsyncExecutor());
}
I am using ExecutorChannel and using my custom Executor as follows:
#Configuration
#EnableAsync
public class AsyncConfiguration extends AsyncConfigurerSupport {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("MyAppThread");
executor.initialize();
return executor;
}
}
I have the following MessageEndpoint which is a subscriber to the eventFilterChannel channel:
#MessageEndpoint
public class MyEventFilter {
#Filter(inputChannel = "eventFilterChannel", outputChannel = "processEventChannel")
public boolean filterEvents(final MyEvent myEvent) {
//filter logic
}
}
Ideally, I would expect my event filter message endpoint to be multi-threaded as I am using ExecutorChannel. I would like to understand if this is the correct implementation of multithreaded endpoint?
However, I am doubtful because I could see the following in my logs:
Channel 'application.eventFilterChannel' has 1 subscriber(s).
Is my implementation correct or is there a standard I can follow?
Well, there is a bit of misleading. Your eventFilterChannel really has only one subscriber - your #Filter. But it is indeed multi-threaded. The same stateless component is used in several threads.
The ExecutorChannel queues incoming tasks and they are performed on the threads in the pool - in parallel. In our case the story is about messages delivery. Not sure if code can help you but it looks like:
public final boolean dispatch(final Message<?> message) {
if (this.executor != null) {
Runnable task = createMessageHandlingTask(message);
this.executor.execute(task);
return true;
}
return this.doDispatch(message);
}
Where that Runnable is like this:
public void run() {
doDispatch(message);
}
...
handler.handleMessage(message);
This handler is exactly a subscriber for that #Filter.
So, the same method is called from different threads. Since this is passive and stateless component it is just safe to keep it only once and reuse from different threads.
On the other hand, out of topic: if you add more subscribers to this channel, they are not going to be called in parallel anyway: By default it is round-robin strategy: the handler for next message is selected according the index.
If one handler fails to process message, we try the next and so on. You can inject any other custom implementation though. Or even reset it to null to always start from the first one.

Categories

Resources