我有一个用@Schedule注释的方法,偶尔会被容器调用。
@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod() throws Exception {
...
}
问题是在某些条件下,我希望此方法抛出异常以导致正在进行的事务回滚。但如果我这样做超过两次,计时器将被清除,不再被调用!
INFO: EJB5119:Expunging timer ['68@@1359143163781@@server@@domain1' 'TimedObject = MyBean' 'Application = My-War' 'BEING_DELIVERED' 'PERIODIC' 'Container ID = 89072805830524936' 'Fri Jan 25 21:49:30 CET 2013' '0' '*/5 # * # * # * # * # * # * # null # null # null # true # myTimerMethod # 0' ] after [2] failed deliveries
我知道我可以使用
在domain.xml中配置计时器重新安排<domains>
...
<configs>
<config>
...
<ejb-container session-store="${com.sun.aas.instanceRoot}/session-store">
<ejb-timer-service>
<property name="reschedule-failed-timer" value="true"></property>
</ejb-timer-service>
</ejb-container>
...
</config>
</configs>
...
</domains>
但我的问题是,我可以在部署应用程序时配置此设置吗?
无法找到:
glassfish-resources.xml
glassfish-ejb-jar.xml
glassfish-web.xml
有没有办法以编程方式进行呢?
(我在配置文件中配置这样的服务器配置而不是配置服务器的理由是这样我的应用程序应该可以直接安装在全新的glassfish上)
答案 0 :(得分:24)
我会使用不同的方法。
不要直接从调度方法中抛出异常,而是尝试引入一个间接级别,如:
...
@Inject RealWorkHere realImplementation;
@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod(){
try{
realImplementation.myTimerMethodImpl()
}catch (Exception x){
// hopefully log it somewhere
}
}
...
其中RealWorkHere
是具有实际实现的bean,如:
@Stateless
public class RealWorkHere{
@TransactionAttribute(REQUIRES_NEW)
public void myTimerMethod() throws Exception {
}
}
这有以下好处:
答案 1 :(得分:5)
如果在执行超时回调方法期间发生应用程序异常,则当前的Glassfish版本4将清除计时器。
应用程序异常导致当前事务的回滚。在这种情况下,Glassfish再次重试错误自由执行超时回调方法。如果再次发生回滚,Glassfish会清除计时器。
我在Glassfish问题跟踪器中提出了一个问题,即在发生重复情况时不要清除计时器。 Glassfish似乎是唯一一个在应用程序异常情况下清除计时器的应用程序服务器。有关详细信息,请参阅glassfish #20749: Glassfish expunges timer even if callback method keeps its contract。您是否愿意为我的问题投票。
我还在EJB规范上提出了一个问题,以阐明EJB容器在这种情况下应该如何表现。有关详细信息,请参阅ejb-spec #111: Please clearify the behaviour of an container if an application exception is thrown during the execution of a timer callback method。