Avoid expunging timer on glassfish

Aksel Willgert picture Aksel Willgert · Jan 25, 2013 · Viewed 8.2k times · Source

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)

Answer

Carlo Pellegrini picture Carlo Pellegrini · Jan 28, 2013

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