Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Schedule methods in EJBs aren't executing after Exceptions

Tags:

ejb

java-ee-6

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

like image 228
t3chris Avatar asked Apr 11 '11 08:04

t3chris


3 Answers

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?

like image 189
Per Lindberg Avatar answered Oct 12 '22 01:10

Per Lindberg


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.

like image 33
Nayan Wadekar Avatar answered Oct 12 '22 02:10

Nayan Wadekar


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.

like image 27
Reitffunk Avatar answered Oct 12 '22 03:10

Reitffunk