I have an EJB timer in an ear, deployed on JBoss 6.4. In 99% of all cases the timer works fine, but sometimes it takes a bit too long to finish and throws a PersistenceException: Transaction was rolled back in a different thread!
.
I have found that this is due to a transacion timeout value that is too low. I do not want to edit the default value but rather override the method-specific timeout. To solve this I split the functionality into two methods: one method annotated with @Timeout
and one which actually does the work.
Here is my timer implememntation:
@Singleton
public class MyTimer implements SomeTimerInterface {
@EJB
private SomeManager myManager;
@Resource
private TimerService timerService;
private Timer timer;
@Override
public void startTimer() {
// Timer scheduled to fire every 7th minute
ScheduleExpression schedule = new ScheduleExpression();
schedule = schedule.hour("*").minute("*/7").second("00");
TimerConfig config = new TimerConfig();
config.setPersistent(false);
timer = timerService.createCalendarTimer(schedule, config);
}
@Timeout
@AccessTimeout(value = 20, unit = TimeUnit.MINUTES)
public void handleTimeout() {
workInNewThread();
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@TransactionTimeout(unit = TimeUnit.SECONDS, value = 900)
public void workInNewThread() {
// This can take anything from 1 sec to 15 min.
List<Object> objects = myManager.getAllTheDatabaseObjects();
}
}
However, the timer seems to ignore the TransactionTimeout as it still times out after 5 minutes (default value). How can I override the default timeout to make sure that the timer finishes the job?
Not sure whether I get it correct. From your code it look like you call workInNewThread() from your @Timeout method, but there is a method cleanup() with a Tx attribute.
I guess that you call methods in the same bean from your @Timeout. But in this case the annotations, neither @TxAttribute nor TxTimeout, will take effect as the container does not control the internal method invocation. You need to use a different EJB or a self reference to let the controller do that work. Other option is to annotate the timeout method directly.