I've got a method in a Java EE6 Singleton Session Bean which is called by a @Schedule(...) timer every 30 seconds. This works as expected until an exception is thrown and catched in the method (exception is throw and catched in a try-catch block). After the exception occurs the timer stops calling the method.
How can i force the timer to recall the method again, regardless if an exception has occured or not?
Best regards,
christian
A related discussion is found at http://www.java.net/node/706287 .
It turns out that if an exception is thrown inside a @Schedule method, that method will be called again after 5 seconds, and if THAT fails, the timer just DIES. No more calls, ever.
That's baad if you e.g. regularly want to do some supervision.
So my solution is to enclose all code in the @Schedule method in a try block and catch ALL Exceptions, log them, and return as if everything is ok.
If there's a more elegant way of doing this, I'd love to hear it.
Edit: Nope, just adding a try {...} catch (Exception e) {...} is not a watertight solution. I still get a dead @Schedule sometimes. Perhaps the JEE container does something obscure when there's a database transaction problem? Nayan: could you elucidate on what you're saying on the matter?
As mentioned in documentation :
The optional persistent element takes a Boolean value and is used to specify whether the automatic timer should survive a server restart or crash. By default, all automatic timers are persistent.
An enterprise bean usually creates a timer within a transaction. If this transaction is rolled back, the timer creation also is rolled back. Similarly, if a bean cancels a timer within a transaction that gets rolled back, the timer cancellation is rolled back. In this case, the timer’s duration is reset as if the cancellation had never occurred.
If the timer fails after encountering exception, then the possible approach left will be to create a new timer manually within the catch block.
I think, I have a solution for that problem. My problem was also, that the timer was deleted, if EJB/JPA errors occurred.
I've just tried to solve this problem with CDI Events, because I wanted the Exception, that could be thrown to be at another place, so the @Schedule
doesn't get touched. I thought using cdi events will decouple the @Schedule
from the startSomeEvent
-Method. It does not. (I don't know, why programming is such a stone age science sometimes) But the trick does the @Asynchronous
-Annotation on the startSomeEvent
-Method.
So, I've implemented a @Singleton
TimerService
, which is used for all the timers I have in my application:
@Singleton
public class TimerService implements Serializable {
@Inject
private Event<SomeEvent> someEvent;
@Schedule(hour = "*", second = "0", minute = "*", persistent = false)
public void fireSomeEvent() {
someEvent.fire(new SomeEvent());
}
}
The SomeEvent
-Event is observed by the method, which actually is doing the stuff you want. Here in example it is creating a Person
with a username
. The username
is UNIQUE
, so the second time the event fires it will throw a MySQLIntegrityConstraintViolationException: Duplicate entry 'uniqueUsername' for key 'USERNAME'
. This would kill our @Schedule
, but it does not, because we have the @Asynchronous
-Annotation.
@Singleton
public class TimerTestService {
@PersistenceContext(unitName = "VWMam3PU")
private EntityManager entityManager;
@Asynchronous
public void startSomeEvent(@Observes SomeEvent event) {
Person p = new Person();
p.setUsername("uniqueUsername");
entityManager.persist(p);
}
}
The SomeEvent
-Class is a simple POJO:
public class SomeEvent {
}
So, I was looking for a solution to that for long time. Now it is working for me. It fires exception and is trying that again and again and again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With