0
votes

I'm writing a scheduled task in Thorntail that will run for a long time (approx. 30 minutes). However, it appears that Thorntail limits the execution time to 30 seconds.

My code looks like this (I've removed code that I believe is irrelevant):

@Singleton
public class ReportJobProcessor {

    @Schedule(hour = "*", minute = "*/30", persistent = false)
    public void processJobs() {
        // Acquire a list of jobs

        jobs.forEach(this::processJob);
    }

    private void processJob(ReportJob job) {
        // A long running process
    }
}

After 30 seconds, I see the following in my logs:

2019-10-01 16:15:14,097 INFO [org.jboss.as.ejb3.timer] (EJB default - 2) WFLYEJB0021: Timer: [id=... timedObjectId=... auto-timer?:true persistent?:false timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@42478b98 initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Tue Oct 01 16:20:00 CEST 2019 timerState=IN_TIMEOUT info=null] will be retried

Another 30 seconds later, an exception is thrown because the job still didn't complete.

I have no idea how to increase the timeout, and googling my issue returns nothing helpful.

How can I increase the timeout beyond 30 seconds?

1
I'm afraid I can't really help, but I'm 100% sure this behavior comes from WildFly. If you can get help on how to configure EJB timers in WildFly to avoid this behavior, it's most likely very easy to transfer to Thorntail. - Ladicek

1 Answers

1
votes

I suggest you take a bit different approach.

The scheduled task will distribute jobs to asynchronously running stateless session beans (SLSB) called ReportJobExecutor and finish immediately after job distribution without timing out. The number of simultaneously running SLSBs can be adjustable in project-defaults.yml, the default count is 16, IIRC. This is a very basic example but demonstrates Java EE executions with predefined bean pool that is invoked using EJB Timer. More complicated example would be manual pooling of executors that would allow you to control lifecycle of the executors (e.g. killing them after specified time).

@Singleton
public class ReportJobProcessor {

    @Inject ReportJobExecutor reportJobExecutor;

    @Schedule(hour = "*", minute = "*/30", persistent = false)
    public void processJobs() {
        // Acquire a list of jobs

        jobs.forEach(job -> reportJobExecutor.run(job));
    }
}

@Stateless
@Asynchronous
public class ReportJobExecutor {

    public void run(ReportJob job) {
        //do whatever with job
    }
}

Idea #2: Another approach would be using Java Batch Processing API (JSR 352), unfortunately, I am not familiar with this API.