在回滚时取消ejb计时器

时间:2014-11-17 13:36:40

标签: java java-ee timer jboss7.x ejb-3.1

有没有办法确保在发生异常时取消定期(每10秒)和持久定时器? @Timeout方法的实现类似于此(从遗留代码中简化):

@Timeout
@TransactionAttribute(REQUIRES_NEW)
public void onTimeout(Timer timer) {
    try {
        doSomeBusinessLogic();
    } catch (Exception e) {
        // throwing this exception makes sure rollback is triggered
        throw new EJBException(e);
    }
}

doSomeBusinessLogic()中发生任何异常时,需要回滚其事务。这工作正常。但是,我还要确保取消定时器。

直接的解决方案是将timer.cancel()放入catch块。但是,这不起作用,因为取消也将被回滚(JEE6 Turorial):

  

企业bean通常在事务中创建一个计时器。如果回滚此事务,则还会回滚计时器创建。 同样,如果bean取消了回滚的事务中的计时器,则会回滚计时器取消。在这种情况下,计时器的持续时间将被重置,就好像取消从未发生过一样。

如果发生异常/回滚,如何确保取消定时器(防止进一步超时)?设置最大重试次数也是足够的,但我不认为这是JBoss支持的。

应用服务器是JBoss AS 7.2。

3 个答案:

答案 0 :(得分:2)

  1. 您可以从计时器bean
  2. 创建新的转换(调用下一个EJB)
  3. 您可以更改TA @TransactionAttribute(NEVER)并从计时器bean创建新的转换(调用下一个EJB)
  4. 将timer.cancel()放入catch块

答案 1 :(得分:2)

我也试过谢尔盖提出的解决方案,它似乎工作 - 计时器被取消。在JBoss EAP 6.2上测试。 这是我用于测试的代码:

@Stateless
public class TimeoutTest implements TimeoutTestLocal {

@Resource
TimerService timerService;

@Resource
SessionContext sessionContext;

@Timeout
@TransactionAttribute(TransactionAttributeType.NEVER)
public void tmout(javax.ejb.Timer timer) {
    try {
        System.out.println("timout invoked");
        //instead of internal call let's invoke doNothing as
        //this timeout callback is client of TimeoutTest EJB
        //in this way doNothing will be run inside transaction
        TimeoutTestLocal local = sessionContext.getBusinessObject(TimeoutTestLocal.class);
        local.doNothing();  
    } catch (Exception e) {
        timer.cancel();
        System.out.println("Timer cancelled");
    }
}

@Override 
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doNothing() {
    throw new EJBException("RE Exception");
}


@Override
public void schedule() {
    timerService.createTimer(5000, 10000, "test");
}
}

答案 2 :(得分:0)

我也有类似的情况,但是在catch子句中取消计时器似乎是可行的。我之所以需要这样做,是为了迫使容器(Wildfly)不要重试失败的超时。

代码看起来像这样:

@Timeout
public void onTimeout(Timer timer) {
    try {
        //the other ejb has @TransactionAttribute(TransactionAttributeType.SUPPORTS)
        doSomeBusinessLogicInSomeOtherEjbThatThrowsEjbException();
    } catch (EJBException e) {
        timer.cancel();
        throw e;//this is not necessary since the EJB context has already getRolledBack = true at this point
    }
}