避免在玻璃鱼上清除计时器

2022-09-01 23:18:01

我有一个用@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

我知道我可以在域中配置计时器重新调度.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

有没有一些方法可以通过编程方式做到这一点?

(我之所以将这样的服务器配置放在配置文件中而不是配置服务器,是因为我的应用程序应该可以直接安装在玻璃鱼的全新安装上)


答案 1

我会使用不同的方法。

与其直接从计划方法引发异常,不如尝试引入一个间接寻址级别,如下所示:

...
@Inject RealWorkHere realImplementation;

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod(){
  try{
     realImplementation.myTimerMethodImpl()
  }catch (Exception x){
   // hopefully log it somewhere
  }
}
...

其中 是具有实际实现的 bean,如:RealWorkHere

@Stateless
public class RealWorkHere{
   @TransactionAttribute(REQUIRES_NEW)
   public void myTimerMethod() throws Exception {

   }
}

这具有以下优点:

  • 不在容器启动的事务中引发异常(从而避免清除)
  • 更好地记录异常
  • 明确划分“真实”业务交易

另请参见


答案 2

当前 Glassfish 到版本 4 如果在超时回调方法的执行期间发生应用程序异常,则会清除计时器。

应用程序异常会导致当前事务的回滚。在这种情况下,Glassfish 会再次重试超时回调方法的无错误执行。如果再次发生回滚,Glassfish 将清除计时器。

我在Glassfish问题跟踪器中提出了一个问题,以便在发生紧急情况时不要删除计时器。Glassfish似乎是唯一一个在应用程序异常的情况下清除计时器的应用程序服务器。请参阅 glassfish #20749:即使回调方法保留其合约以获取更多详细信息,Glassfish 也会清除计时器。愿你为我的问题投票。

我还在 EJB 规范上提出了一个问题,以阐明 EJB 容器在这种情况下的行为方式。请参阅 ejb-spec #111:如果在执行计时器回调方法期间引发应用程序异常,请清除容器的行为以获取更多详细信息。


推荐