使用 EJB 异步方法的正确方法
Correct way to use EJB Asynchronous methods
我有两个任务需要执行,比如 task1
和 task2
,它们是同一业务流程的一部分。我必须在 task1
完成后向最终用户做出响应,因此必须将响应时间降至最低。
我目前的方法是执行 task1
并在 task1
完成后立即异步调用 task2
方法。 task2
很复杂,它的响应时间是我无法控制的,因为它有一些外部依赖性。
@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
}
}
在 websphere 8.0(使用的 EJB 容器)中,同步方法和异步方法由不同的线程池 运行。
我最初的假设是,即使 task2
表现不佳,task1
也不会产生任何影响,但很遗憾,事实并非如此。
如果task2
表现不佳,异步线程池中的所有线程都会被占用。这将导致 task1
等待异步线程空闲,因此 task1
会产生影响。
webspherere 服务器日志中的消息:
The request buffer for thread pool WorkManager.WebSphere_EJB_Container_AsynchMethods_Internal_WorkManager has reached its capacity
我的问题是什么是实现我在这里想要实现的目标的正确方法。
我觉得@AccessTimeout is what you are looking for. I see an example here
这将限制 .doTask2() 可以 运行 的时间并避免您的问题。
@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
}
}
替代方案:
要限制异步进程可以占用的时间,请使用 handle.get(xx, TimeUnit.xx);方法。您还需要 return Future 而不仅仅是 void 才能使其正常工作。
我希望这适合您的用例,因为您需要调用 .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);
}
}
另一种选择是在管理控制台中增加 "EJB asynchronous method invocation settings" 的 "Work request queue size"。这是一个队列,在实际线程池本身之前,因此这可能会给您争取更多时间。
理想情况下,这应该与上面建议的超时结合使用。
我有两个任务需要执行,比如 task1
和 task2
,它们是同一业务流程的一部分。我必须在 task1
完成后向最终用户做出响应,因此必须将响应时间降至最低。
我目前的方法是执行 task1
并在 task1
完成后立即异步调用 task2
方法。 task2
很复杂,它的响应时间是我无法控制的,因为它有一些外部依赖性。
@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
}
}
在 websphere 8.0(使用的 EJB 容器)中,同步方法和异步方法由不同的线程池 运行。
我最初的假设是,即使 task2
表现不佳,task1
也不会产生任何影响,但很遗憾,事实并非如此。
如果task2
表现不佳,异步线程池中的所有线程都会被占用。这将导致 task1
等待异步线程空闲,因此 task1
会产生影响。
webspherere 服务器日志中的消息:
The request buffer for thread pool WorkManager.WebSphere_EJB_Container_AsynchMethods_Internal_WorkManager has reached its capacity
我的问题是什么是实现我在这里想要实现的目标的正确方法。
我觉得@AccessTimeout is what you are looking for. I see an example here 这将限制 .doTask2() 可以 运行 的时间并避免您的问题。
@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
}
}
替代方案:
要限制异步进程可以占用的时间,请使用 handle.get(xx, TimeUnit.xx);方法。您还需要 return Future 而不仅仅是 void 才能使其正常工作。
我希望这适合您的用例,因为您需要调用 .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);
}
}
另一种选择是在管理控制台中增加 "EJB asynchronous method invocation settings" 的 "Work request queue size"。这是一个队列,在实际线程池本身之前,因此这可能会给您争取更多时间。
理想情况下,这应该与上面建议的超时结合使用。