我有以下情况。我有一份工作:
我们当前的解决方案使用一个线程,该线程在存在一段时间之后会抛出异常,而不会被外部进程打断,但是由于这显然打破了EJB标准,我们试图用其他一些解决它装置
有什么想法吗?
编辑添加:当然,已经超时的作业也需要删除(或中断)。
编辑添加2: 这个问题似乎没有任何解决方案,因为检测死锁似乎几乎不可能坚持纯EJB3标准。由于下面的Enno Shioji的评论反映了这一点,我将他的建议作为正确的答案。
答案 0 :(得分:1)
使用Bean Managed Transaction,可以使用UserTransaction接口指定特定事务的超时。
修改超时值 与交易相关联 由当前线程与开始 方法
void setTransactionTimeout(int seconds) throws SystemException
稍微解决一下,它应该在给定的场景中正常工作。
编辑也可以使用服务器特定属性来管理事务超时。
JBoss :在类或方法级别,可以应用注释@TransactionTimeout(100)
。
Weblogic :在weblogic-ejb-jar.xml中指定参数
<transaction-descriptor>
<trans-timeout-seconds>100</trans-timeout-seconds>
</transaction-descriptor>
GlassFish :在sun-ejb-jar.xml中使用可选的cmt-timeout-in-seconds
元素
答案 1 :(得分:1)
这更像是一个澄清请求,但它太长了,不适合作为评论..
我不知道你现在是怎么做的,因为从你写的内容来看,使用请求处理线程似乎是要走的路。像这样:
//Some webservice method (synchronous)
public Result process(Blah blah){
try{
return getResult(TimeUnit.SECONDS, 10);
}catch(InterruptedException e){
//No result within 10 seconds!
throw new ServiceUnavailableException("blah");
}
}
我不确定你为什么要创建线程。如果您被迫使用线程,因为getResult
方法根本没有超时,那么您将遇到线程泄漏。如果它在较长时间后超时,因此您想要“快速”回复用户,那么这将是我考虑使用线程的唯一情况,就像我想象您如何使用它一样。这可能导致线程在负载下堆积,我会努力避免这种情况。
也许您可以发布一些代码并让我们知道您在服务中创建的原因是什么?
另外,你的客户端界面是什么?听起来像是一个同步的web服务还是什么?
<小时/> 在那种情况下,如果我是你,我会使用
HashedWheelTimer
作为单身人士......这种机制应该适合您的要求(here is an implementation)。但是,遗憾的是,这似乎与EJB规范中禁止线程和禁止单例的禁令相冲突。实际上,如果你这样做,确实没有问题。例如,请参阅this discussion。我们还在EJB应用程序中使用了单例模式。用过JBoss。但是,如果这不是一个可行的选择,那么我可能会考虑通过定义一个新的Web服务(并将其部署在Web容器或其他东西中)来隔离其自己的JVM中的处理,并从EJB应用程序调用该服务。然而,这显然会导致性能下降,现在你将有另一个全新的应用程序。
答案 2 :(得分:1)
将进程及其超时线程粘贴到使用@WebService注释的类中,将该类放入WAR中,然后从EJB调用WebService。
WAR没有相同的限制或与EJB相同的合同生效,因此可以安全地运行线程。
是的,我认为这是一个“黑客”,但它符合要求的字母,并且它是可移植的。
答案 3 :(得分:0)
您可以使用commonj WorkManager创建线程。 WebSphere和Weblogic内置了实现,因为他们提出了标准,但您也可以找到其他应用服务器的实现。
基本上,WorkManager允许您在容器内创建托管线程,就像在常规Java中使用Executor一样。你唯一的另一种选择是使用MDB,但这将是一个“更重”的解决方案。
由于我不知道你的实际平台,你必须自己google commonj与你的平台8 - )
注意:这不是一个实际的标准,但它可以广泛用于不同的平台,并且应该很好地适合您的目的。
答案 4 :(得分:0)
对于EJB,有一个“容器管理事务”的概念。通过在bean或特定方法上指定@TransactionAttribute,容器将在调用方法时创建事务。如果代码的执行时间超过事务阈值,则容器将抛出异常。如果呼叫在事务阈值下完成,它将照常返回。您可以在调用代码中捕获异常并适当地处理它。
有关容器管理的交易的详情,请查看:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html和http://download.oracle.com/javaee/5/tutorial/doc/bncij.html
答案 5 :(得分:0)
您可以使用@TimeOut
。类似的东西:
@Stateless
public class TimedBean {
@Resource
private TimerService timerService;
static private AtomicInteger counter = new AtomicInteger(0);
static private Map<Integer, AtomicBoolean> canIRunStore = new ...;
public void doSomething() {
Integer myId = counter.getAndIncrement();
AtomicBoolean canIRun = new AtomicBoolean(true);
canIRunStore.put(myId, canIRun);
timerService.createTimer(1000, 0, myId);
while (canIRun.get() /* && some other condition */) {
// do my work ... untill timeout ...
}
}
@Timeout
@PermitAll
public void timeout(Timer timer) {
Integer expiredId = (Integer) timer.getInfo();
AtomicBoolean canHeRun = canIRunStore.get(expiredId);
canIRunStore.remove(expiredId);
canHeRun.set(false);
}
}