Reputation: 4413
I have two tasks that I need to perform say task1
and task2
which are a part of same business process. I have to give response to the end user when task1
completes so it's response time have to be minimized.
My current approach is to perform task1
and as soon as task1
is finished, invoke task2
method asynchronously. task2
is complicated and it's response time is out of my control as it has some external dependency.
@Stateless
public class SessionBean1 {
@Inject
SessionBean2 sessionBean2;
public void doTask1(){
// task one stuff
sessionBean2.doTask2();
}
}
@Stateless
public class SessionBean2 {
@Asynchronous
public void doTask2(){
// do task2 stuff
}
}
In websphere 8.0 (the EJB container in use) synchronous methods and asynchronous methods are run by different thread pools.
My initial assumption was that even if task2
is performing badly, task1
would have no impact, but sadly that's not true.
If task2
is performing badly, all threads from asynchronous thread pool will be occupied. This will cause task1
to wait for asynchronous threads to be free and hence task1
has impact.
The message in websphrere server logs :
The request buffer for thread pool WorkManager.WebSphere_EJB_Container_AsynchMethods_Internal_WorkManager has reached its capacity
My question is what would be a proper way to achieve what I'm trying to achieve here.
Upvotes: 6
Views: 26316
Reputation: 11838
I think @AccessTimeout is what you are looking for. I see an example here This will limit the amount of time that .doTask2() can run and avoid your problem.
@Stateless
public class SessionBean1 {
@Inject
SessionBean2 sessionBean2;
public void doTask1(){
// task one stuff
sessionBean2.doTask2();
}
}
SessionBean2
@Stateless
public class SessionBean2 {
@AccessTimeout(60000)//default timeunit is TimeUnit.MILLISECONDS
@Asynchronous
public void doTask2(){
// do task2 stuff
}
}
As an alternative :
To limit the time the async process can take, use the handle.get(xx, TimeUnit.xx); method. You will also need to return Future and not just void to make it work.
I hope this suits your use case as you will need to call a .get
@Stateless
public class SessionBean1 {
@Inject
SessionBean2 sessionBean2;
public void doTask1(){
// task one stuff
Future<Void> handle = sessionBean2.doTask2();
// do other stuff
handle.get(10, TimeUnit.SECONDS);//If you want to block later
}
}
SessionBean2
@Stateless
public class SessionBean2 {
@Asynchronous
public Future<Void> doTask2(){
// do task2 stuff
new AsyncResult<Void>(Void);
}
}
Upvotes: 2
Reputation: 5090
Another alternative would be to increase the "Work request queue size" of the "EJB asynchronous method invocation settings" in the Admin Console. This is a queue, before the actual thread pool itself, so this might buy you some more time.
Ideally this should be used in combination with the timeouts suggested above.
Upvotes: 3