【发布时间】:2014-12-01 11:11:56
【问题描述】:
假设我们有这个类:
@Startup
@Singleton(mappedName = "workflow", name = "workflow")
@ConcurrencyManagement(value = ConcurrencyManagementType.BEAN)
public class Workflow implements WorkflowInterfaceLocal, WorkflowInterfaceRemote {
private Object msg;
public <T> Future<Object> doTask(T msg) {
for(int i=0; i<10;i++) {
try {
Thread.sleep(1000);
if(i==5) {
throw new RuntimeException("a");
}
System.out.println("DOTASK" + (i+1));
} catch(InterruptedException ex) {
//e
}
}
}
public void setTimer(long intervalDuration) {
LOG.debug("Setting a programmatic timeout for " + intervalDuration
+ " milliseconds from now.");
timerService.createTimer(intervalDuration, null);
}
@Timeout
private void executeOnTimeout(Timer t){
LOG.debug("start - doTask with timer timeout");
t.cancel(); //execute one time and cancel the timer
doTask(this.msg);
LOG.debug("end - doTask with timer timeout");
}
}
这个类应该异步调用executeOnTimeout,这将调用doTask方法。
我是这样称呼它的:
WorkflowInterfaceRemote workflow = lookupRemoteEJB(WorkflowInterfaceRemote.class);
workflow.setTimer(0);
成功了,方法被成功调用,调用者方法没有挂起,所以@Timeout注解的方法被异步调用了。
也许你注意到doTask 方法中的RuntimeException。我把它放在那里有一个特定的原因:如果doTask 触发(无论出于何种原因)RuntimeException,EJB 容器会重新启动它,所以输出是:
[01/12/14 11.49.27:258 CET] 00000017 SystemOut O DOTASK1
[01/12/14 11.49.28:258 CET] 00000017 SystemOut O DOTASK2
[01/12/14 11.49.29:258 CET] 00000017 SystemOut O DOTASK3
[01/12/14 11.49.30:259 CET] 00000017 SystemOut O DOTASK4
[01/12/14 11.49.31:259 CET] 00000017 SystemOut O DOTASK5
[01/12/14 11.49.38:274 CET] 00000017 LocalExceptio E [Exception stack trace]
[01/12/14 11.49.33:272 CET] 00000017 SystemOut O DOTASK1
[01/12/14 11.49.34:273 CET] 00000017 SystemOut O DOTASK2
[01/12/14 11.49.35:273 CET] 00000017 SystemOut O DOTASK3
[01/12/14 11.49.36:274 CET] 00000017 SystemOut O DOTASK4
[01/12/14 11.49.37:274 CET] 00000017 SystemOut O DOTASK5
[01/12/14 11.49.38:274 CET] 00000017 LocalExceptio E [Exception stack trace]
我正在阅读this article,这是一篇意大利文,我将在这里翻译相关部分(名为“Timer e transazioni”):
定时器和事务
计时器的创建和取消是事务性的。这意味着如果事务在创建或取消计时器后执行回滚,则其创建或取消将中止。此外,考虑到计时器是异步的,因此没有事务传播,而是在调用回调方法时创建了一个新事务(就像它具有 REQUIRES_NEW 属性一样)。 如果此事务失败或执行回滚,容器会尝试至少执行一次。
现在,如果我理解正确的话,如果 @Timeout 方法触发了一个 execption,那么事务就会失败并且 EJB 容器会尝试重新调用该方法。
这对我来说是一种不受欢迎的行为,无论有什么异常,我都希望始终执行一次 @Timeout 方法。
为什么不使用
@Asynchronous注释而不是@Timeout?
因为我使用的是 Websphere 8,该注释存在一个已知错误。 IBM 说它在他们发布的一些修复包中得到了修复,但我使用的是最新的修复包,问题仍然存在,所以这不是一个选项。
为什么不使用
WorkManager和Work来代替?
因为我似乎必须使用 IBM 的工作管理器实现类,并且我想让我的代码尽可能不依赖于服务器。
有没有办法告诉容器不要再次尝试执行我的方法?
【问题讨论】:
-
出于好奇:为什么要为无状态 bean 指定
@ConcurrencyManagement注释?此注释适用于单例 bean。 -
@slwk 好问题。我忘了包括单例注释。实际上,这是从我的代码中提取的示例,其中
Workflow类扩展了CommonWorkflow类,它是一个单例 bean。我包括它。
标签: java jakarta-ee timer transactions ejb