Hot questions for Using Enterprise JavaBeans in timer

Question:

Am I doing anything wrong?

import java.util.Date;
import java.util.Timer;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.TimerService;

@Singleton
@LocalBean
@Startup
public class CIScheduler {

    @Resource
    private TimerService timerService;

    @PostConstruct
    public void init() {
        timerService.createTimer(1000, 5000, "myTimerInterval");
    }

    @Timeout
    public void execute(Timer timer) {
        System.out.println("Current Time : " + new Date());
    }
}

Stack: JDK 8, Wildfly 10

Error LOG:

09:31:31,781 WARN [org.jboss.as.ejb3] (EJB default - 9) WFLYEJB0161: Failed to reinstate timer 'config-api.config-api.CIScheduler' (id=f571b03a-efa 9-467d-a9de-b17d88bf54c7) from its persistent state 09:31:31,783 ERROR [org.jboss.as.ejb3] (EJB default - 9) WFLYEJB0022: Error duri ng retrying timeout for timer: [id=35f55f82-a982-43d8-bece-42cfc89debe8 timedObj ectId=config-api.config-api.CIScheduler auto-timer?:false persistent ?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@1eef0fd init ialExpiration=Wed Jun 15 09:20:46 BRT 2016 intervalDuration(in milli sec)=5000 n extExpiration=Wed Jun 15 09:31:36 BRT 2016 timerState=RETRY_TIMEOUT info=myTimer Interval]: javax.ejb.EJBException: java.lang.IllegalArgumentException: ja va.lang.ClassCastException@1da01b2

Samples extracted from: https://examples.javacodegeeks.com/enterprise-java/ejb3/timer/ejb-timer-service-example/

UPDATE: I cleaned the data and tmp folder and the error log changed to:

09:49:42,178 INFO [org.jboss.as.ejb3] (EJB default - 2) WFLYEJB0021: Timer: [id =26b74afb-625d-4007-a786-1c0caa92a70b timedObjectId=configuracao-api.config-api.CIScheduler auto-timer?:false persistent?:true timerService=org.jboss.as.e jb3.timerservice.TimerServiceImpl@1b701e2 initialExpiration=Wed Jun 15 09:49:37 BRT 2016 intervalDuration(in milli sec)=5000 nextExpiration=Wed Jun 15 09:49:47 BRT 2016 timerState=IN_TIMEOUT info=myTimerInterval] will be retried 09:49:42,179 INFO [org.jboss.as.ejb3] (EJB default - 2) WFLYEJB0023: Retrying t imeout for timer: [id=26b74afb-625d-4007-a786-1c0caa92a70b timedObjectId=config-api.config-api.CIScheduler auto-timer?:false persistent?:true timerS ervice=org.jboss.as.ejb3.timerservice.TimerServiceImpl@1b701e2 initialExpiration =Wed Jun 15 09:49:37 BRT 2016 intervalDuration(in milli sec)=5000 nextExpiration =Wed Jun 15 09:49:47 BRT 2016 timerState=IN_TIMEOUT info=myTimerInterval] 09:49:42,181 ERROR [org.jboss.as.ejb3] (EJB default - 2) WFLYEJB0022: Error duri ng retrying timeout for timer: [id=26b74afb-625d-4007-a786-1c0caa92a70b timedObj ectId=config-api.config-api.CIScheduler auto-timer?:false persistent ?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@1b701e2 init ialExpiration=Wed Jun 15 09:49:37 BRT 2016 intervalDuration(in milli sec)=5000 n extExpiration=Wed Jun 15 09:49:47 BRT 2016 timerState=RETRY_TIMEOUT info=myTimer Interval]: javax.ejb.EJBException: java.lang.IllegalArgumentException: argument type mismatch at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInt erceptor.java:187) .......


Answer:

The method annotated with @Timeout is only allowed to have an argument from type javax.ejb.Timer. You inadvertently imported Timer from the util package (java.util.Timer). If you fix the import, the timer should work like a charm :).

Question:

I've been following the example of Adam Bean to do a timer, but it doesn't work properly. I created an @Singleton EJB with a method which is annoted with @Schedule. The application is deployed to a wildfly 11. I have two problems here. The first is, that my timer logs every second, instead of every minute. The second problem is, that every time the time is triggered, I get an error message.

Could someone give me a hint, what do I do wrong? Maybe I'm just blind and cant see it.

My class:

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import java.util.logging.Logger;

@Singleton
public class DeviceTrackerCronJob {

    private static final Logger LOG = Logger.getLogger(DeviceTrackerCronJob.class.getName());

    private long counter;

@Schedule(second = "*", minute = "*/1", hour = "*", info = "Every Minute!")
public void execute() {
    LOG.info("### --- FAKING SOME CONTENT " + counter++);
    }
}

The message I get is:

12:42:03,025 INFO [de.klemensmorbe.tracking.DeviceTrackerCronJob] (EJB default - 1) ### --- FAKING SOME CONTENT 575 12:42:04,040 ERROR [org.jboss.as.ejb3.timer] (EJB default - 1) WFLYEJB0020: Error invoking timeout for timer: [id=a797d1ca-e550-41e4-bfe7-46066f7b24b3 timedObjectId=web.web.DeviceTrackerCronJob auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@c39b6bb initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Wed Jan 03 12:42:05 UTC 2018 timerState=IN_TIMEOUT info=null]: java.lang.RuntimeException: WFLYEJB0343: Cannot invoke timeout method because method null is not a timeout method at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:83) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:109) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.CalendarTimerTask.invokeBeanMethod(CalendarTimerTask.java:66) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.CalendarTimerTask.callTimeout(CalendarTimerTask.java:53) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimerTask.run(TimerTask.java:160) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimerServiceImpl$Task$1.run(TimerServiceImpl.java:1220) at org.wildfly.extension.request-controller//org.wildfly.extension.requestcontroller.RequestController$QueuedTask$1.run(RequestController.java:497) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.base/java.lang.Thread.run(Thread.java:844) at org.jboss.threads//org.jboss.threads.JBossThread.run(JBossThread.java:320)

12:42:04,041 INFO [org.jboss.as.ejb3.timer] (EJB default - 1) WFLYEJB0021: Timer: [id=a797d1ca-e550-41e4-bfe7-46066f7b24b3 timedObjectId=web.web.DeviceTrackerCronJob auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@c39b6bb initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Wed Jan 03 12:42:05 UTC 2018 timerState=IN_TIMEOUT info=null] will be retried 12:42:04,041 INFO [org.jboss.as.ejb3.timer] (EJB default - 1) WFLYEJB0023: Retrying timeout for timer: [id=a797d1ca-e550-41e4-bfe7-46066f7b24b3 timedObjectId=web.web.DeviceTrackerCronJob auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@c39b6bb initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Wed Jan 03 12:42:05 UTC 2018 timerState=IN_TIMEOUT info=null] 12:42:04,042 ERROR [org.jboss.as.ejb3.timer] (EJB default - 1) WFLYEJB0022: Error during retrying timeout for timer: [id=a797d1ca-e550-41e4-bfe7-46066f7b24b3 timedObjectId=web.web.DeviceTrackerCronJob auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@c39b6bb initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Wed Jan 03 12:42:05 UTC 2018 timerState=RETRY_TIMEOUT info=null]: java.lang.RuntimeException: WFLYEJB0343: Cannot invoke timeout method because method null is not a timeout method at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:83) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:109) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.CalendarTimerTask.invokeBeanMethod(CalendarTimerTask.java:66) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.CalendarTimerTask.callTimeout(CalendarTimerTask.java:53) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimerTask.retryTimeout(TimerTask.java:234) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimerTask.run(TimerTask.java:168) at org.jboss.as.ejb3//org.jboss.as.ejb3.timerservice.TimerServiceImpl$Task$1.run(TimerServiceImpl.java:1220) at org.wildfly.extension.request-controller//org.wildfly.extension.requestcontroller.RequestController$QueuedTask$1.run(RequestController.java:497) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.base/java.lang.Thread.run(Thread.java:844) at org.jboss.threads//org.jboss.threads.JBossThread.run(JBossThread.java:320)


Answer:

my timer logs every second, instead of every minute.

Then set the second to the second of minute when it should run. If you want it to run at 12:00:00, then 12:01:00 (i.e. at second 0 of each minute), then use second = "0".

You probably also want persistent set to false, unless you want the server to catch up with the missed schedules if it's down at some point.

I'm not sure why you are getting the timeout error.

Question:

I want a process to run everyday at an specific hour of the day everyday. I want to use the Timerservice of EJB's but I can only find how to set an interval, not an specific hour of the day:

@Resource
    protected TimerService timerService;

    @Timeout
public void timeoutHandler(Timer timer) {
    String name = timer.getInfo().toString();
    System.out.println("Timer name=" + name);
}

public void startOrModifyTimer(long initialExpiration, long interval, String name){      
    //Cancel previous timer
    Collection<Timer> timers = timerService.getAllTimers();
    for (Timer timer: timers) {
        if (timer.getInfo().equals(name)) {
            timer.cancel();
        }
    }

    TimerConfig config = new TimerConfig();
    config.setInfo(name);
    config.setPersistent(false);
    timerService.createIntervalTimer(initialExpiration, interval, config);
}

I want to change the timer from "Every day at 2am" to "Everyday at 3am" on runtime.


Answer:

You want:

createCalendarTimer(ScheduleExpression schedule) 

The ScheduleExpression will do what you want.

Question:

I am using J2EE to write a web application. Some where in my application I needed to have a timer, so I decided to use EJB timer on my server side. But the problem is at moment, when I started the server the timer automatically starts to work, But I have to be able to stop and start timer from client side.


Answer:

You'll need to add remote interface methods on the EJB that manually cancel and recreate the EJB timer. There is no standard EJB API for stopping/restarting EJB timers, and there is no standard client API for even cancelling/creating timers

Question:

I can get all timers in a EJB module using getAllTimers() on TimerService. These timers run on different EJB's. Is there a way to know on which bean a Timer runs? Or is the only way explicitly setting this in the Timer info at creation time?


Answer:

You can get additional info about each timer. But you need to cast timers to classes from container implementation.

Question:

Hi I am implementing a web application with email sending functionality. In order for our email server not to be blacklisted we have to send at most one email per 5 seconds. So I was thinking to create an @Singleton EJB Email sender, in that way only one EJB instance will be responsible for sending all the emails in whole application. How should I implement the 5 seconds counter in order to send at most 1 email per 5 seconds? e.g the class will look like that

  @Singleton
  public class EmailSender {
       public void sendEmail(String msg){
                 ....
       }
  }

Answer:

Try using @Schedule:

@Singleton
public class EmailSender {
     Queue<Email> queue;

     @Schedule(second = "*/5", minute = "*", hour = "*")
     public void sendEmail(String msg){
          if (!queue.isEmpty()) {
               //get queue element and send email
          }
     }
}