Re-scheduling a task that executes once using Spring Trigger - java

I have a requirement where I need to schedule a task (from UI) that will execute only once. After completion, I should be able to re-schedule (from UI) the same task again.
I know #Schedule won't work here as I need to execute only once. So after further searching I am able to schedule the task to execute only once at specific time using TaskScheduler with Runnable and Date and also along with #Async. However I am unable to make it reschedule.
Looks like using quartz might be possible, but I haven't gone through it yet.
Is it possible to implement my requirement with Spring Trigger. I can see only two implementation of trigger interface CronTrigger and PeriodicTrigger.
Please suggest any possible approaches.
Including initial piece of code would be helpful.

The easiest way I see would be to create a regularly scheduled "trigger" method in a Spring bean that checks a certain condition and only executes the "real" action when the condition is met (e.g. the time you entered in the UI is in the past and the job has not started yet):
#Scheduled(fixedDelay = 5000)
public void trigger() {
if(condition){
//... do the action
}
}
This requires some persistence to store the "job metadata" like the execution date and the current state of the job, but that seems "lighter" than working with threads or including quartz just for this one use case.

Related

Spring Boot - check if target date is reached for objects

I don't know if it's a real question or not... But i'd like to know how some of you will approach this...
I have a Spring Boot application.
Then I have a Interruttore.class, which has, among others this field timeoutDatewhich is a Date.
In the app, various instances of this class are used. The timeoutDate field can be updated, for every single object, by various factors. I need to know when the actual date reaches the timeutDate.
In a very simple (and not optimized) way i would have created a #Scheduled task, but the delay will be too short and i don't like it, how can i do?
In a very simple (and not optimized) way i would have created a
#Scheduled task, but the delay will be too short and i don't like it,
how can i do?
Why too short ?
You can use the delay you wish.
#Scheduled(fixedDelay=50000) // 50 secs
#Scheduled(fixedDelay=1000) // 1 secs
Look at the documentation for Spring's various task scheduling APIs: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
You have plenty of choices. I think the "not optimised" idea you might have is to schedule a repeating task which searches your beans to find the expired ones. That would indeed be inefficient for large numbers of beans.
You could simply create a scheduled task for each bean with a timeoutDate, created at the same time as that bean, and when its timeoutdate is updated (Spring AOP could help with this).
Alternatively you could keep a list of beans, sorted by timeout date. Schedule a task for the time of the earliest expiry. It reaps that bean and any others who's time is past, then schedules a new task for the time of the next expiry.
If you do this, you need to make sure that:
- it handles new objects added to the list (perhaps with an expiry date earlier than the currently scheduled cull)
- it handles the case where an object is removed for a reason other than a timeout
(Unless neither of those things can happen -- in which case don't worry about it!)
You can use Quartz or Jesque(redis). Whatever task needs to be executed, you can schedule that task at that time.
If this time value can be updated anytime, you can cancel(unschedule) the previously scheduled task(using task identifiers or keys) and reschedule it with the updated time.

Is there a way to simulate a trigger misfire in Quartz? (Java)

I'm looking for a way to simulate or force a trigger misfire programatically. Here's the scenario:
I have a job set to trigger but the job requires some underlying resource that may be unavailable at times. If the resource is unavailable, I would like Quartz to re-fire the trigger later based on the misfire policy.
I've explored two options that are similar but not quite what I'm looking for:
Throwing a JobExecutionException with refireImmediately set to true:
Works, but doesn't delay execution based on misfire policy; this
would hammer the resource availability check.
Scheduling a second trigger at some fixed interval of time in the
future: Also works, but doesn't take into account misfire policy.
This means a job could wind up with a bunch of retries queued up
stemming from different failed runs.
Any ideas or anything I'm missing? Thanks!
If I got it right, you don't need to force or simulate a misfire because the resource availability is "something your Job can handle".
Misfires exists and are managed by Quartz for situations like server shutdown or other "unexpected problems" that prevent Job execution.
You have two options to follow to implement a simple fault-tolerance retry logic;
your Job can execute it's logic only when the underlying resource is available, so you can:
Wait for the resource to become availabile:
in this case your job waits and repeat the check for the resource availability, eventually after a short timeout, the job can give up and end.
Just do nothing if the resource is not available:
in this case the job ends without doing anything and the it will fire normally and retry according the Trigger definition.
In both cases, if the resource is avaliable, the Job can execute it's inner logic and use the underlying resource. (No misfires, because the Job was actually executed)
This can be done using a Trigger, setting the misfire policy you need in case the Job cannot be executed at all. See This great and detailed article on Quartz misfires.
In your situation, If you want to execute a job one time every day:
Define a Cron trigger that fires multiple times in a day in a given span of time, for exemple, every 15 minutes from 8:00 AM to 12:00 AM:
0 0/15 8-12 * * ?
Buld a Job that use one of the two approaches described before
The first time your Job inner logic executes (that is, the resource is available) your job will save a "job executed flag" with the day of execution somewhere on DB.
On the following trigger executions, the Job will check the flag and will not execute it's inner logic again.
Also, if your job will take long time to finish, you may want to prevent concurrent execution of the same job using the following annotation on the job implementation:
#DisableConcurrentExecution
See Quartz tutorials for more informations on job execution.

How to execute more then one method of a spring bean on app startup

I have a spring bean with 4 blocking queues. Each queue is assigned a method (named processQueueX() ) which calls take() on that queue and processes taken object from queue.
I want to call each of those method in a separate thread on app startup.
I tried with task scheduler and fixed-delay setting but that in some way blocks tomcat and it stops responding to requests. Each method needs to be called once, so scheduling was a bad idea I guess.
Init method does not work also since it works in a single thread, each method has endless loop to process queue forever.
Is there a way to call these methods declaratively from spring config file in manner similar to task namespace? Or programmatically?
Tnx
I think using scheduler not a bad idea use quart scheduler with simple trigger thus quarz will do threading for you and tomcat not effected .And configure quartz with just enough number of thread.
Would 23.4. The Spring TaskExecutor abstraction help?
Where the example has a MessagePrinterTask class, you would have similar, but your run() method would access one of the queues. You would set up your Spring config to inject one of the queues into the task, so depending on how similar your queues are, you might be able to use the same Runnable task.

EJB timer performance

I am trying to decide if use a java-ee timer in my application or not. The server I am using is Weblogic 10.3.2
The need is: After one hour of a call to an async webservice from an EJB, if the async callback method has not been called it is needed to execute some actions. The information regarding if the callback method has been called and the date of the execution of the call is stored in database.
The two possibilities I see are:
Using a batch process that every half hour looks for all the calls that have been more than one hour without response and execute the needed actions.
Create a timer of one hour after every single call to the ws and in the #Timeout method check if the answer has come and if it has not, execute the required actions.
From a pure programming point of view, it looks easier and cleaner the second one, but I am worry of the performance issues I could have if let's say there are 100.000 Timer created at a single moment.
Any thoughts?
You would be better off having a more specialized process. The real problem is the 100,000 issue. It would depend on how long your actions take.
Because its easy to see that each second, the EJB timer would fire up 30 threads to process all of the current pending jobs, since that's how it works.
Also timers are persistent, so your EJB managed timer table will be saving and deleting 30 rows per second (60 total), this is assuming 100K transactions/hour.
So, that's an lot of work happening very quickly. I can easily see the system simply "falling behind" and never catching up.
A specialized process would be much lighter weight, could perhaps batch the action calls (call 5 actions per thread instead of one per thread), etc. It would be nice if you didn't have to persist the timer events, but that is what it is. You could almost easily simply append the timer events to a file for safety, and keep them in memory. On system restart, you can reload that file, and then roll the file (every hour create a new file, delete the older file after it's all been consumed, etc.). That would save a lot of DB traffic, but you could lose the transactional nature of the DB.
Anyway, I don't think you want to use the EJB Timer for this, I don't think it's really designed for this amount of traffic. But you can always test it and see. Make sure you test restarting your container see how well it works with 100K pending timer jobs in its table.
All depends of what is used by the container. e.g. JBoss uses Quartz Scheduler to implement EJB timer functionality. Quartz is pretty good when you have around 100 000 timer instances.
#Pau: why u need to create a timer for every call made...instead u can have a single timer thread created at start up of application which runs after every half-hour(configurable) period of time and looks in your Database for all web services calls whose response have not been received and whose requested time is past 1 hour. And for selected records, in for loop, it can execute required action.
Well above design may not be useful if you have time critical activity to be performed.
If you have spring framework in your application, you may also look up its timer services.http://static.springsource.org/spring/docs/1.2.9/reference/scheduling.html
Maybe you could use some of these ideas:
Where I'm at, we've built a cron-like scheduler which is powered by a single timer. When the timer fires the system checks which crons need to run using a Quartz CronTrigger. Generally these crons have a lot of work to do, and the way we handle that is each cron spins its individual tasks off as JMS messages, then MDBs handle the messages. Currently this runs on a single Glassfish instance and as our task load increases, we should be able to scale this up with a cluster so multiple nodes are processing the jms messages. We balance the jms message processing load for each type of task by setting the max-pool-size in glassfish-ejb-jar.xml (also known as sun-ejb-jar.xml).
Building a system like this and getting all the details right isn't trivial, but it's proving really effective.

Java library class to handle scheduled execution of "callbacks"?

My program has a component - dubbed the Scheduler - that lets other components register points in time at which they want to be called back. This should work much like the Unix cron service, i. e. you tell the Scheduler "notify me at ten minutes past every full hour".
I realize there are no real callbacks in Java.
Here's my approach, is there a library which already does this stuff? Feel free to suggest improvements, too.
Register call to Scheduler passes:
a time specification containing hour, minute, second, year month, dom, dow, where each item may be unspecified, meaning "execute it every hour / minute etc." (just like crontabs)
an object containing data that will tell the calling object what to do when it is notified by the Scheduler. The Scheduler does not process this data, just stores it and passes it back upon notification.
a reference to the calling object
Upon startup, or after a new registration request, the Scheduler starts with a Calendar object of the current system time and checks if there are any entries in the database that match this point in time. If there are, they are executed and the process starts over. If there aren't, the time in the Calendar object is incremented by one second and the entreis are rechecked. This repeats until there is one entry or more that match(es). (Discrete Event Simulation)
The Scheduler will then remember that timestamp, sleep and wake every second to check if it is already there. If it happens to wake up and the time has already passed, it starts over, likewise if the time has come and the jobs have been executed.
Edit: Thanks for pointing me to Quartz. I'm looking for something much smaller, however.
Lookup Quartz
If your objects know exactly the individual points in time which they wish to be executed, then you could use a java.util.concurrent.ScheduledExecutorService. Then they simple call:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
long timeToExecute = ... //read from DB? use CronTrigger?
long delayToExecution = timeToExecute - System.currentTimeMillis();
scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS);
You'd only need to use Quartz if you want the scheduler itself to handle functionality like "execute every 5 seconds", or if you want complex behaviour around missed executions, or the persistence of the execution audit trail.
You can actually trivially re-use Quartz's CronTrigger class to get a "next execution time". The class is completely standalone and does not depend on being invoked from within the Quartz "context". Once you have the next execution time as a Date or long, you can just use the Java ScheduledExecutorService as above
If your needs are simple, consider using java.util.Timer:
public class TimerDemo {
public static void main(String[] args) {
// non-daemon threads prevent termination of VM
final boolean isDaemon = false;
Timer timer = new Timer(isDaemon);
final long threeSeconds = 3 * 1000;
final long delay = 0;
timer.schedule(new HelloTask(), delay, threeSeconds);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
Date oneMinuteFromNow = calendar.getTime();
timer.schedule(new KillTask(timer), oneMinuteFromNow);
}
static class HelloTask extends TimerTask {
#Override
public void run() {
System.out.println("Hello");
}
}
static class KillTask extends TimerTask {
private final Timer timer;
public KillTask(Timer timer) {
this.timer = timer;
}
#Override
public void run() {
System.out.println("Cancelling timer");
timer.cancel();
}
}
}
As has been noted, the ExecutorService of java.util.concurrent offers a richer API if you need it.
Quartz is the big and obvious powerhouse in this area, but there are some alternatives to explore.
Cron4j is a decent enough library, that is a little more lightweight than Quartz. It provides good documentation and will do what you want.
Probably more interesting is if you want to use a library that fits better with Java's concurrency libraries (particularly Executors and ScheduledExecutors) then HA-JDBC has a CronExecutorService interface, implemented by its CronThreadPoolExecutor. Now, interestingly, it has a dependency on Quartz (to provide the CronExpression class), but I find that the two together work better than just Quartz alone. If you don't want large dependencies, its easy to extract the handful of classes from Quartz and HA-JDBC that make this happen.
Since you want something much smaller (just noticed your edit), grab CronExpression from Quartz, and the two HA-JDBC classes I mentioned above. That'll do it.
I would strongly recommend cron4j (already mentioned) over Quartz, unless you absolutely need some of more advanced and complex features of Quartz. Cron4j focuses nicely on what it is supposed to do, has decent documentation, and is not a kitchen-sink solution.
Quartz scheduler is usually recommended.
Can't believe java.util.Timer was voted as the answer. Quartz is really a much better choice.
A big advantage of quartz over java.util.Timer is that with quartz the jobs can be stored in the db. As a result one jvm can schedule and another can execute. Also (obviously) the request survives across jvm restarts.
Probably more interesting is if you want to use a library that fits better with Java's concurrency libraries (particularly Executors and ScheduledExecutors) then HA-JDBC has a CronExecutorService interface, implemented by its CronThreadPoolExecutor. Now, interestingly, it has a dependency on Quartz (to provide the CronExpression class), but I find that the two together work better than just Quartz alone. If you don't want large dependencies, its easy to extract the handful of classes from Quartz and HA-JDBC that make this happen.
I just wanted to say that I tried extracting these classes, and it worked! I needed these three classes:
CronExpression (quartz)
CronThreadPoolExecutor (ha-jdbc)
DaemonThreadFactory (ha-jdbc)
And I only had to do these minor tweaks:
Removing the logger from CronThreadPoolExecutor (it was created but never used)
Moved the constant YEAR_TO_GIVEUP_SCHEDULING_AT from CronTrigger to CronExpression
I was thrilled that I didn't get stuck pull in a tangle of dependencies. Congrats to the class authors!
And it's been working like a champ.

Categories