Avoid expunging timer on glassfish
Asked Answered
C

2

24

I have a method annotated with @Schedule that is called by the container once in a while.

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod() throws Exception {
    ...
}

Problem is on certain conditions i want to this method to throw an exception to cause the ongoing transaction to rollback. But if I do this more than two times the timer will be expunged and not called any more!

INFO: EJB5119:Expunging timer ['68@@1359143163781@@server@@domain1' 'TimedObject = MyBean' 'Application = My-War' 'BEING_DELIVERED' 'PERIODIC' 'Container ID = 89072805830524936' 'Fri Jan 25 21:49:30 CET 2013' '0' '*/5 # * # * # * # * # * # * # null # null # null # true # myTimerMethod # 0' ] after [2] failed deliveries

I know i can configure timer rescheduling in domain.xml using

<domains>
    ...
    <configs>
        <config>
            ...
            <ejb-container session-store="${com.sun.aas.instanceRoot}/session-store">
               <ejb-timer-service>
                     <property name="reschedule-failed-timer" value="true"></property>
                </ejb-timer-service>
            </ejb-container>
            ...
        </config>
    </configs>
    ...
</domains>

But my question is, can I have this setting configured when i deploy my application?

Can't find it in:

glassfish-resources.xml
glassfish-ejb-jar.xml
glassfish-web.xml

Is there some way to do it programmatically maybe?

(My rationale behind behind putting server-configuration like this in config files rather than configuring the server is so my app should be possible to install directly on a fresh installation of glassfish)

Caxton answered 25/1, 2013 at 21:30 Comment(1)
For someone suffering from asynchronous contexts, https://mcmap.net/q/583194/-schedule-methods-in-ejbs-aren-39-t-executing-after-exceptionsHalfcock
D
26

I'd use a different approach.

Instead of throwing an exception directly from the scheduled method, try to introduce a level of indirection as in:

...
@Inject RealWorkHere realImplementation;

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void myTimerMethod(){
  try{
     realImplementation.myTimerMethodImpl()
  }catch (Exception x){
   // hopefully log it somewhere
  }
}
...

where RealWorkHere is the bean with the actual implementation as in:

@Stateless
public class RealWorkHere{
   @TransactionAttribute(REQUIRES_NEW)
   public void myTimerMethod() throws Exception {

   }
}

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

See also

Duleba answered 28/1, 2013 at 8:46 Comment(6)
According to the javadoc for @Schedule: Timeout callback methods must not throw application exceptions.Felty
I tried this (but kept the methods in same slsb), problem is the timer still get expunged. I get the improved logging etc.. tho, so it is an improvement. Will try to separate it into different bean (to follow your example to the point), but it is not obvious to me why that would have an impact.Caxton
@AkselWillgert I use two beans as a simple mean to obtain separate transactions, otherwise using two methods whithout special constructs would enroll both in the same transaction as the annotation are not processed on thisDuleba
I understand, Moving it into another class was a factor and solved my problem. Awesome not having to do glassfish specific configuration for this!Caxton
Hi @Carlo Pellegrini, your approach worked perfectly for me over the last few years. Up to the point that my (inner) myTimerMethodImpl() timed out (EJB5123: Rolling back timed out transaction) and threw a RollbackException. In this case the (outer) myTimerMethod() method annotated with die @Schedule annotation also timed out and eventually led to the EJB5119:Expungung timer. Any ideas how to deal with timeouts?Bodycheck
Sadly not. The only way I see around it is increasing the timeout of the outer method with @TransactionTimeout but if the inner one is waiting on a blocking call, the timeout may be triggered nonetheless. Going asynchronous might be a better approachDuleba
R
5

The current Glassfish up to version 4 expunges a timer if during the execution of the timeout callback method an application exception occurs.

The application exception causes a rollback of the current transaction. In such a situation Glassfish retries the error free execution of the timeout callback method once again. If a rollback again occurs Glassfish expunges the timer.

I filed an issue in the Glassfish issue tracker not to expunge the timer in case of an excpetion. Glassfish seems to be the only application server who expunges a timer in case of an application exception. See glassfish #20749: Glassfish expunges timer even if callback method keeps its contract for more details. May you would like to vote for my issue.

I also filed an issue on the EJB specification to clarify how the EJB container should behave in such situations. See ejb-spec #111: Please clearify the behaviour of an container if an application exception is thrown during the execution of a timer callback method for more details.

Reggy answered 18/8, 2013 at 21:5 Comment(1)
I didn't notice your answer down here and just added those exact links to Carlo's answer. Thanks for your efforts on this, Oliver.Tapir

© 2022 - 2024 — McMap. All rights reserved.