【问题标题】:Avoid expunging timer on glassfish避免在 glassfish 上删除计时器
【发布时间】:2013-01-09 22:37:45
【问题描述】:

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

【问题讨论】:

标签: java glassfish java-ee-6 ejb-3.1


【解决方案1】:

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

应用程序异常导致当前事务回滚。在这种情况下,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

【讨论】:

  • 我没有注意到您的答案,只是将这些确切的链接添加到 Carlo 的答案中。感谢您为此付出的努力,奥利弗。
【解决方案2】:

我会使用不同的方法。

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

...
@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 {

   }
}

这带来了以下好处:

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

另见

【讨论】:

  • 根据@Schedule 的javadoc:超时回调方法不能抛出应用程序异常。
  • 我试过这个(但将方法保留在同一个 slsb 中),问题是计时器仍然被删除。我得到了改进的日志记录等。但是,这是一个改进。将尝试将其分成不同的 bean(以您的示例为重点),但我不清楚为什么会产生影响。
  • @AkselWillgert 我使用两个 bean 作为获取单独事务的简单方法,否则使用两个没有特殊构造的方法将在同一事务中注册,因为 this 上未处理注释
  • 我明白,将它移到另一个类是一个因素,解决了我的问题。真棒,不必为此做 glassfish 特定的配置!
  • 遗憾的是没有。我看到的唯一方法是使用@TransactionTimeout 增加外部方法的超时,但是如果内部方法正在等待阻塞调用,则仍然可能会触发超时。异步可能是更好的方法
猜你喜欢
  • 2018-09-27
  • 2013-02-15
  • 2018-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
  • 2019-08-06
  • 2015-06-06
  • 1970-01-01
相关资源
最近更新 更多