EJB #Schedule wait until method completed - java

I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:
#Schedule(minute = "*/1", hour = "*")
which is working fine.
However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.
Is it somehow possible, to terminate the scheduler if the current execution is not completed?

If only 1 timer may ever be active at the same time, there are a couple of solutions.
First of all the #Timer should probably be present on an #Singleton. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.
The following is basically enough:
#Singleton
public class TimerBean {
#Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
atSchedule is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.
Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
try {
workerBean.doTimerWork();
} catch (Exception e) {
System.out.println("Timer still busy");
}
}
}
The worker bean:
#Singleton
public class WorkerBean {
#AccessTimeout(0)
public void doTimerWork() throws InterruptedException {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
}
}
This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
The worker bean:
#Singleton
public class WorkerBean {
private AtomicBoolean busy = new AtomicBoolean(false);
#Lock(READ)
public void doTimerWork() throws InterruptedException {
if (!busy.compareAndSet(false, true)) {
return;
}
try {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
} finally {
busy.set(false);
}
}
}
There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.

I ran into the same problem but solved it slightly differently.
#Singleton
public class DoStuffTask {
#Resource
private TimerService timerSvc;
#Timeout
public void doStuff(Timer t) {
try {
doActualStuff(t);
} catch (Exception e) {
LOG.warn("Error running task", e);
}
scheduleStuff();
}
private void doActualStuff(Timer t) {
LOG.info("Doing Stuff " + t.getInfo());
}
#PostConstruct
public void initialise() {
scheduleStuff();
}
private void scheduleStuff() {
timerSvc.createSingleActionTimer(1000l, new TimerConfig());
}
public void stop() {
for(Timer timer : timerSvc.getTimers()) {
timer.cancel();
}
}
}
This works by setting up a task to execute in the future (in this case, in one second). At the end of the task, it schedules the task again.
EDIT: Updated to refactor the "stuff" into another method so that we can guard for exceptions so that the rescheduling of the timer always happens

Since Java EE 7 it is possible to use an "EE-aware" ManagedScheduledExecutorService, i.e. in WildFly:
In for example a #Singleton #Startup #LocalBean, inject the default "managed-scheduled-executor-service" configured in standalone.xml:
#Resource
private ManagedScheduledExecutorService scheduledExecutorService;
Schedule some task in #PostConstruct to be executed i.e. every second with fixed delay:
scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);
scheduleWithFixedDelay:
Creates and executes a periodic action that becomes enabled first
after the given initial delay, and subsequently with the given delay
between the termination of one execution and the commencement of the
next.[...]
Do not shutdown the scheduler in i.e. #PreDestroy:
Managed Scheduled Executor Service instances are managed by the
application server, thus Java EE applications are forbidden to invoke
any lifecycle related method.

well I had a similar problem. There was a job that was supposed to run every 30 minutes and sometimes the job was taking more than 30 minutes to complete in this case another instance of job was starting while previous one was not yet finished.
I solved it by having a static boolean variable which my job would set to true whenever it started run and then set it back to false whenever it finished. Since its a static variable all instances will see the same copy at all times. You could even synchronize the block when u set and unset the static variable.
class myjob{
private static boolean isRunning=false;
public executeJob(){
if (isRunning)
return;
isRunning=true;
//execute job
isRunning=false;
}
}

Related

How to test ScheduledExecutorService exception handling in Junit?

I have a task which I scheduled to run every 30 mins. I used ScheduledExecutorService to schedule.
I want to test(junit) the exception handling for ScheduledExecutorService such that when ever there is an exception thrown, the thread is not dying because of the exception.
My code :
public enum MonitorTask {
TIMER;
private final AtomicBoolean isPublishing = new AtomicBoolean(false);
private final long period = 18000000
public synchronized boolean initialize() {
return initialize(period, period);
}
/**
* #return true, if call was successful i.e. Timer task was scheduled
*/
boolean initialize(long delay, long period) {
if (isPublishing.get()) {
log.warn("Already monitoring for new feature data");
return false;
}
//execute on daemon thread
ScheduledExecutorService scheduledExecutorService =
Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
}
);
Runnable runnableTask = () -> {
try {
DataPublisher.INSTANCE.update(DateTime.now());
} catch (Throwable e) {
log.warn("Failed to check for new Data!", e);
}
};
scheduledExecutorService.scheduleAtFixedRate(runnableTask, delay, period, TimeUnit.MILLISECONDS);
isPublishing.set(true);
return true;
}
}
As for now, my unit test check for the functionality:
public class MonitorTaskTest {
#Test
public void testInitialize() throws Exception {
AtomicInteger val = new AtomicInteger(0);
DataProvider provider = testProvider(val);
assertEquals(0, val.get());
// this should update val every 10 ms ( adds 1 to val )
Assert.assertTrue(MonitorTask.TIMER.initialize(0, 10));
assertEquals(0, val.get());
DataPublisher.INSTANCE.registerForNewData(provider, DateTime.now());
// wait for 3 updates
Thread.sleep(10 * 3);
Assert.assertTrue("Expected val to be >= 3 but is " + val.get(), val.get() >= 3);
}
#Before
public void setUp() {
DataPublisher.INSTANCE.clear();
}
private static DataProvider testProvider(final AtomicInteger ai) {
return new DataProvider() {
private AtomicInteger val = ai;
#Override public boolean update(DateTime dateTime) throws Exception {
val.incrementAndGet();
return true;
}
#Override public boolean exists(DateTime dateTime) {
return true;
}
#Override public void close() throws Exception {
}
};
}
}
I think you are going down the wrong rabbit hole here. Meaning: when you check the javadoc for the method you are using, you find:
Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.)
In other words: you are asking how to test something that is guaranteed to work by the Java system library you are using. And in that sense you are wasting your time.
You might rather spend time to improve your code to make it easier to test. You see - when your class would receive an ExecutorService object (instead of creating one for itself) you could pass in a same thread executor for your unit tests. And all of a sudden, your unit tests can run on one thread which makes the whole testing a lot easier - as it allows you to get rid of your sleep statements in your tests. (and those sleep statements are much more of a problem than chances that threads are not re-started although the system library guarantees you to do so).
Beyond that: your runnable is already written in a way that should guarantee that threads running this code never die (of course, it is questionable to catch Throwable). But in order to test that, I guess you only need another "test provider" where update() throws any kind of exception.

When to shutdown ScheduledExecutorService?

I have a singleton that needs to start a scheduled execution. This is the code:
public enum Service{
INSTANCE;
private Service() {
startAutomaticUpdate();
}
private void startAutomaticUpdate() {
try {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new AutomaticUpdate(), 0, 15, TimeUnit.MINUTES);
} catch (Exception e) {
LOG.error(e.getMessage() + "Automatic update not working: ");
}
}
//Makes a call to a webservice that updates a static variable.
private void getTemplateNames(){...}
private class AutomaticUpdate implements Runnable {
public AutomaticUpdate() {
}
#Override
public void run(){
try{
getTemplateNames();
}catch(Exception e){
LOG.error("Error in automatic update: "+e.getMessage());
}
}
}
I am not sure when or if I should call the shutdown method of the executor. I'm using JEE5, so I'm not sure if simply undeploying the app will automatically execute the shutdown, or if I am messing up big time and creating a ridiculous amount of threads and not killing them.
-EDIT-
I'll add a bit more info, just in case.
The whole app is a RESTful web app using Jersey as a ServletContainer.
You said JEE5? Why you're reeinventing the wheel?
Just create a EJB with #Schedule and #Startup
#Singleton
#Startup
public class TaskSingleton {
#Schedule(second = "0", minute = "*/15", hour = "*")//This mean each 15:00 minutes
public void getTemplateNames() {
// YOUR TASK IMPLEMENTATION HERE
}
}
No you don't mean JEE5 complaint server. :(
Go for the implementation with a ServletContextListener. I wrote some answer like that here, It's the same idea, it does applies here.

TimerService EJB initialize multiple times

In one hand I've a CronScheduler class which is meant to starts once per application an configure a TimerService.
In the other hand I've a heavy task (annotated as #EJB) which I want to call in the #timeout of the timer. Note that in the timer, I create a thread which calls p.go()
The code:
#Singleton
#Startup
public class CronScheduler {
#EJB
Processor p;
#Resource
private TimerService timerService;
#PostConstruct
public void init() {
String h = ... // h,m ,s work fine
String m = ...
String s = ...
ScheduleExpression conf = new ScheduleExpression();
conf.hour(h);
conf.minute(m);
conf.second(s);
// I've tried with the second param (TimerConfig) enabled and disabled
timerService.createCalendarTimer(conf, new TimerConfig("msg ", false));
LOG.log(Level.INFO, ">> Ready for: " + conf.toString());
}
#Timeout
public void run() {
LOG.log(Level.INFO, "Calling the process");
Thread t = new Thread() {
#Override
public void run() {
super.run();
p.go();
}
};
t.start();
}
}
The point is, the cron is initialize multiple times. The #PostConstruct code runs N times. In the logs I see.
Ready for: A-B-C
Ready for: A-B-C
Ready for: A-B-C
The consequences are p.go() is called multiple times. Is the #singleton annotation working fine?
Perhaps you have more than one timer running? I recently encountered a weird scenario where timer was set to 1k ms and the new one started before the previous one finished. Adding some kind of lock fixed it for me. Maybe it's similar case.
You could debug and check how many threads you have active.
Finally I got; it's a matter of EJB and hand-made threads. The point wasn't the Timer itself but the creation of a new thread which is not handled by the EJB magic.
#Singleton
#Startup
public class CronScheduler {
#EJB
Processor p;
#Resource
private TimerService timerService;
#PostConstruct
public void init() {
String h = ... // h,m ,s work fine
String m = ...
String s = ...
ScheduleExpression conf = new ScheduleExpression();
conf.hour(h);
conf.minute(m);
conf.second(s);
timerService.createCalendarTimer(conf, new TimerConfig("desc msg ", false));
LOG.log(Level.INFO, ">> Ready for: " + conf.toString());
}
#Timeout
public void run() {
LOG.log(Level.INFO, "Calling the process");
p.go();
}
}

Manually trigger a #Scheduled method

I need advice on the following:
I have a #Scheduled service method which has a fixedDelay of a couple of seconds in which it does scanning of a work queue and processing of apropriate work if it finds any. In the same service I have a method which puts work in the work queue and I would like this method to imediately trigger scanning of the queue after it's done (since I'm sure that there will now be some work to do for the scanner) in order to avoid the delay befor the scheduled kicks in (since this can be seconds, and time is somewhat critical).
An "trigger now" feature of the Task Execution and Scheaduling subsystem would be ideal, one that would also reset the fixedDelay after execution was initiated maually (since I dont want my manual execution to collide with the scheduled one). Note: work in the queue can come from external source, thus the requirement to do periodic scanning.
Any advice is welcome
Edit:
The queue is stored in a document-based db so local queue-based solutions are not appropriate.
A solution I am not quite happy with (don't really like the usage of raw threads) would go something like this:
#Service
public class MyProcessingService implements ProcessingService {
Thread worker;
#PostCreate
public void init() {
worker = new Thread() {
boolean ready = false;
private boolean sleep() {
synchronized(this) {
if (ready) {
ready = false;
} else {
try {
wait(2000);
} catch(InterruptedException) {
return false;
}
}
}
return true;
}
public void tickle() {
synchronized(this) {
ready = true;
notify();
}
}
public void run() {
while(!interrupted()) {
if(!sleep()) continue;
scan();
}
}
}
worker.start();
}
#PreDestroy
public void uninit() {
worker.interrup();
}
public void addWork(Work work) {
db.store(work);
worker.tickle();
}
public void scan() {
List<Work> work = db.getMyWork();
for (Work w : work) {
process();
}
}
public void process(Work work) {
// work processing here
}
}
Since the #Scheduled method wouldn't have any work to do if there are no items in the work-queue, that is, if no one put any work in the queue between the execution cycles. On the same note, if some work-item was inserted into the work-queue (by an external source probably) immediately after the scheduled-execution was complete, the work won't be attended to until the next execution.
In this scenario, what you need is a consumer-producer queue. A queue in which one or more producers put in work-items and a consumer takes items off the queue and processes them. What you want here is a BlockingQueue. They can be used for solving the consumer-producer problem in a thread-safe manner.
You can have one Runnable that performs the tasks performed by your current #Scheduled method.
public class SomeClass {
private final BlockingQueue<Work> workQueue = new LinkedBlockingQueue<Work>();
public BlockingQueue<Work> getWorkQueue() {
return workQueue;
}
private final class WorkExecutor implements Runnable {
#Override
public void run() {
while (true) {
try {
// The call to take() retrieves and removes the head of this
// queue,
// waiting if necessary until an element becomes available.
Work work = workQueue.take();
// do processing
} catch (InterruptedException e) {
continue;
}
}
}
}
// The work-producer may be anything, even a #Scheduled method
#Scheduled
public void createWork() {
Work work = new Work();
workQueue.offer(work);
}
}
And some other Runnable or another class might put in items as following:
public class WorkCreator {
#Autowired
private SomeClass workerClass;
#Override
public void run() {
// produce work
Work work = new Work();
workerClass.getWorkQueue().offer(work);
}
}
I guess that's the right way to solve the problem you have at hand. There are several variations/configurations that you can have, just look at the java.util.concurrent package.
Update after question edited
Even if the external source is a db, it is still a producer-consumer problem. You can probably call the scan() method whenever you store data in the db, and the scan() method can put the data retrieved from the db into the BlockingQueue.
To address the actual thing about resetting the fixedDelay
That is not actually possible, wither with Java, or with Spring, unless you handle the scheduling part yourself. There is no trigger-now functionality as well. If you have access to the Runnable that's doing the task, you can probably call the run() method yourself. But that would be the same as calling the processing method yourself from anywhere and you don't really need the Runnable.
Another possible workaround
private Lock queueLock = new ReentrantLock();
#Scheduled
public void findNewWorkAndProcess() {
if(!queueLock.tryLock()) {
return;
}
try {
doWork();
} finally {
queueLock.unlock();
}
}
void doWork() {
List<Work> work = getWorkFromDb();
// process work
}
// To be called when new data is inserted into the db.
public void newDataInserted() {
queueLock.lock();
try {
doWork();
} finally {
queueLock.unlock();
}
}
the newDataInserted() is called when you insert any new data. If the scheduled execution is in progress, it will wait until it is finished and then do the work. The call to lock() here is blocking since we know that there is some work in the database and the scheduled-call might have been called before the work was inserted. The call to acquire lock in findNewWorkAndProcess() in non-blocking as, if the lock has been acquired by the newDataInserted method, it would mean that the scheduled method shouldn't be executed.
Well, you can fine tune as you like.

Work manager using thread.sleep or delay doesn't work

I used Spring framework and oracle weblogic 10.3 as a container.
I used workmanager for manage my thread, I already made one thread that managed by workmanager. Fortunately spring provide the delegation class for using workmanager, so I just need to put it on applicationContext.xml.
But when I put the "while" and TimeUnit for sleep the process on desired delayed time, the deployment process never finished. It seems the deployment process never jump out from while loop for finishing the deployment.
Why?, As I know using typical thread, there is no issue like this. Should I use another strategy for make it always loop and delay.
import java.util.concurrent.TimeUnit;
import org.springframework.core.task.TaskExecutor;
public class TaskExecutorSample{
Boolean shutdown = Boolean.FALSE;
int delay = 8000;
TimeUnit unit = TimeUnit.SECONDS;
private class MessageGenerator implements Runnable {
private String message;
public MessageGenerator(String message){
this.message = message;
}
#Override
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
public TaskExecutorSample(TaskExecutor taskExecutor){
this.taskExecutor = taskExecutor;
try {
while (shutdown.equals(Boolean.FALSE)){
this.printMessage();
unit.sleep(delay);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public void printMessage() {
taskExecutor.execute(new MessageGenerator("Print this Messages"));
}
}
Really thanks in advance.
Regards,
Kahlil
Well, the thread will wait for a bit more than 2h. Did you really wait that long for the deployment to finish?
[EDIT] You're probably doing the wait in the wrong place: You should wait in the run() method of the thread, not the constructor of the class.

Categories