14

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

t3chris
  • 1,390
  • 1
  • 15
  • 25

6 Answers6

13

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?

Per Lindberg
  • 737
  • 8
  • 8
  • Yea, that was my thread on java.net. I took the same approach w/the try/catch everything. I can understand the point of unregistering a time that keeps on failing but I think there should be an option to disable this so 'feature' if you want. – NBW May 15 '12 at 14:03
  • Precisely; there should indeed be a new option to @Schedule that allows the method to throw an exception and just call the method again at the next scheduled occasion (and not re-try). Let's hope the JCP Gods are listening... – Per Lindberg May 21 '12 at 12:08
  • I took this approach (try/catch bloque) within @Scheduled method and worked. But i consider should exist an option that allows the method to throw and exception. – Adam M. Gamboa G. Jun 04 '15 at 18:49
  • My concerns with this approach is that the transaction will no be rolled back due to the exception being catched. This could mean that your're halfway through updating the database when the exception occurs and this update is then commit and your data is corrupted... – Runar Halse Apr 22 '16 at 11:02
6

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.

Nayan Wadekar
  • 11,444
  • 4
  • 50
  • 73
3

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.

Malte
  • 1,937
  • 1
  • 15
  • 20
3

If you happen to use Glassfish application server (whereat i am not sure if it is server specific in the first place) have a look at the following answer to the question Avoid expunging timer on glassfish. It helped me a lot.

EDIT (explanation in case of a dead link)

In the linked answer the author Carlo Pellegrini explained that the problem is that the exception happens in the transaction of the schedueled task. If one can outsource the business logic into another EJB which is executed in an other transaction (@TransactionAttribute(REQUIRES_NEW)) the problem would vanish. Furthermore

This comes with the benefit of:

  • Not throwing an exception in a container-initated transaction (thus avoiding the expunging)
  • Better logging of the Exception
  • Clear demarcation of the 'real' business transaction
Community
  • 1
  • 1
Filou
  • 490
  • 4
  • 17
  • Link-only answers are highly discouraged here because the links may become dead in the future. I suggest you edit your answer with quotes from the sources you cite. – Anirudh Sharma Jan 13 '16 at 12:22
0

Since I cannot comment on the previous post from Per Lindberg regarding the watertight exception solution, I'll explain a possible solution here.

I had a similiar problem. I have a schedule update for my caches. However the Schedule should not die on any exception. Because then the application needs to be restarted every time an error occurs to enable the Scheduler again.

This could be solved in my case be separating the container transactions from the database call with a new transaction. You can handle all exceptions in the separate transaction and only forwards those that you anticipate/you can process in your Scheduled method.

Here's an example I found that describes a solution with an interface. It works also without one. In my case I just injected the Singleton bean in itself again and called it.

https://web.archive.org/web/20160511085332/http://www.javahelp.info:80/2009/11/01/using-transactionattribute-in-submethods-on-same-ejb3-beans/

Nick
  • 2,827
  • 4
  • 29
  • 39
Dr4gon
  • 421
  • 8
  • 17
0

One possible solution is using ManagedScheduledExecutorService.

@Stateless
public class MyService {

    @Schedule(hour = "*", minute = "*")
    public void doSome() {
        final Future<?> future = executorService.submit(() -> {
            try {
                doActually();
            } catch (final Exception e) {
                // log it out
            }
        });
    }

    @Resource
    private ManagedScheduledExecutorService executorService;
}
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184