避免在glassfish上删除计时器

Aks*_*ert 22 java glassfish java-ee-6 ejb-3.1

我有一个用@Schedule注释的方法,偶尔会被容器调用.

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod() throws Exception {
    ...
}
Run Code Online (Sandbox Code Playgroud)

问题是在某些条件下,我希望此方法抛出异常以使正在进行的事务回滚.但如果我这样做超过两次,计时器将被清除,不再被调用!

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
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用在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>
Run Code Online (Sandbox Code Playgroud)

但我的问题是,我可以在部署应用程序时配置此设置吗?

找不到它:

glassfish-resources.xml
glassfish-ejb-jar.xml
glassfish-web.xml
Run Code Online (Sandbox Code Playgroud)

有没有办法以编程方式做到这一点?

(将配置文件中的服务器配置放在配置文件而不是配置服务器背后的理由是,我的应用程序应该可以直接安装在全新的glassfish上)

Car*_*ini 25

我会用不同的方法.

不要直接从调度方法中抛出异常,而是尝试引入一个间接级别,如下所示:

...
@Inject RealWorkHere realImplementation;

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

RealWorkHere具有实际实现的bean 在哪里:

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

   }
}
Run Code Online (Sandbox Code Playgroud)

这有以下好处:

  • 不在容器启动的事务中抛出异常(从而避免了删除)
  • 更好地记录异常
  • 明确划分"真正的"商业交易

也可以看看

  • 根据@Schedule的javadoc:Timeout回调方法不能抛出应用程序异常. (2认同)
  • 可惜不是。我看到的唯一方法是使用 `@TransactionTimeout` 增加外部方法的超时,但如果内部方法正在等待阻塞调用,则可能会触发超时。异步可能是更好的方法 (2认同)

Oli*_*ver 5

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

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

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

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