Schedule task depending on its response - java

I'm trying to schedule a task depending on it's response. The task is something like:
public Date scheduledTask() {
Date nextRun;
// ...
nextRun = something();
// ...
return nextRun;
}
How can I make sure that the same task is called again when reaching the nextRun?
Thank you.

This is very simple with standard Quartz scheduler API. Inside your Job compute nextRun time and create a trigger with startAt() defined:
public class ScheduledJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
final Date nextRun = something();
Trigger trigger = newTrigger().
startAt(nextRun).
forJob(context.getJobDetail()).
build();
context.getScheduler().scheduleJob(trigger);
}
}
Tested, works like a charm.

Follow the ideas mentioned here, then you should be able to have:
public class GuaranteeSchedule implements Trigger {
private Future<?> resultForNextRun;
private TaskScheduler scheduler;
public void scheduledTask() {
// 'this' is this trigger that is used by the scheduler
// and the method `nextExecutionTime` is automatically called by the scheduler
resultForNextRun = scheduler.schedule(theTask, this);
// theTask is the object that calls something()
}
// Implementing Trigger to add control dynamic execution time of this trigger
#Override
public Date nextExecutionTime(TriggerContext tc) {
// make sure the result for the previous call is ready using the waiting feature of Future
Object result = resultForNextRun.get();
// Use tc or other stuff to calculate new schedule
return new Date();
}
}
The rest, you should follow the configuration mentioned in the reference. I believe this would resolve the problem of depending the next call of a trigger on the result of the previous. You may also need to be careful about the first call of scheduledTask to make sure resultForNextRun != null.

Related

Can I define job instance using method instead of class Quartz?

I'm reading Quartz documentation and trying to understand can I pass inside Job instance method instead of class.
For example, in case with class I need to write:
public class MyJobClass implements Job {
public MyJobClass() {
// Instances of Job must have a public no-argument constructor.
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
JobDataMap data = context.getMergedJobDataMap();
System.out.println("someProp = " + data.getString("someProp"));
}
}
And defining a Job Instance like:
JobDetail job1 = newJob(MyJobClass.class) // what about method here
.withIdentity("job1", "group1")
.usingJobData("someProp", "someValue")
.build();
By the same principle, I tried to define job instance passing method like:
// define the job
JobDetail job = newJob(testMethod())
.withIdentity("job1", "group1")
.build();
And method looks like:
private Class<? extends Job> testMethod() {
//...
return null;
}
But I get the error:
java.lang.IllegalArgumentException: Job class cannot be null.
Updated:
I return null in method, because if I don't do this I get:
Your testMethod() method returns null. Quartz does not accept null and fails.
Quartz wants to manage jobs by itself so it is why you are only allowed to pass class not instance.
Why do you need to provide your own instance? If you want to make it "persistent" to keep state between executions then Quartz provides stateful job concept, see http://www.quartz-scheduler.org/api/2.3.0/org/quartz/StatefulJob.html

How To Call A Method After A Certain Period

I have a MySQL database running on my localhost. To this database I have JDBC-connection. Over a RESTful WebService a softwareagent puts results into this database. I implemented a garbage collector in Java and want to execute that garbage collector after a certain period. My aim is that I do not have too many entries in the table.
The Garbage Collector looks as follows:
public void collectGarbageResults() {
ArrayList<Integer> ids = new ArrayList<Integer>();
ResultSet rs = this.execQuery("SELECT * FROM results");
try {
while (rs.next()) {
if ( (System.currentTimeMillis()) - (Timestamp.valueOf(rs.getString("tmstmp")).getTime()) > Long.parseLong(appconfigs.get("resultstableactuality")) ) {
ids.add(rs.getInt("id"));
}
}
for (Integer i : ids) {
this.deleteResultsWhereId(i);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
The method I call looks as follows:
private void deleteResultsWhereId(int id) {
retint = this.updateQuery("DELETE FROM results WHERE id=" + id + ";");
}
I am using JSF in an Eclipse's Dynamic Web Project and these methods are implemented in a managed bean. I am going to store the interval in an XML-file which I use for my application's configuration. Over the variable appconfigs I call the method 'get' and ask for the node containing my interval.
Now my question:
How can I call the method of the garbage collector after a certain period in my WebApp?
If you have any questions do not hesitate to comment.
My Solution :
#WebListener
public class BackgroundJobManager implements ServletContextListener{
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
long delayToStart = 0;
long numberOfUnits = 60;
TimeUnit tu = TimeUnit.SECONDS;
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new ExecuteGarbageCollector(), delayToStart, numberOfUnits, tu);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
The class I call implements Runnable as follows:
public class ExecuteGarbageCollector implements Runnable{
#Override
public void run() {
DAO dao = new DAO();
dao.collectGarbageResults();
}
}
You could use ScheduledExecutorService or Quartz
Quartz has a lot of facilities, but If you choose ScheduledExecutorService you don't have to add any new dependencies to your project. and as you just want this scheduled task, it's simple.
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(...);
Take a look at some comments about both in: Quartz vs. ScheduledExecutorService in Java web application
Check out a scheduler library. You can use Quartz for example.
Call Java from MySQL. You could either have this kicked off by a job or trigger
Just stick to SQL and ignore running this in Java. Probably the easiest if you are good at SQL. Then you can encapsulate this in a SPROC or trigger.
It's your choice whether this should live in your web-app or in your database. I've used both methods for executing timed SQL calls and tend to prefer the code oriented approach
The actual question could have well been how to call a function after a specific interval of time?
Take a look at :
How to call a method after some specific interval of time in Java
and
java: run a function after a specific number of seconds

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.

EJB #Schedule wait until method completed

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;
}
}

Reset mysql colum values to default after specific using Servlet

I am new to web development I am making some web services using java servlets, and I am stuck in so many How to do it? stuff :(
I am developing an application in which I need to reset the mysql table column values back to default values at some time let's say we need to reset the counter # every Sunday 10:00 pm.
is there any thing like alarm manager in Java or mysql that can run all the time in background and trigger # specific time.
Thanks,
Java has a good interface ScheduledExecutorService.
You can try this code
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
//every day to execute
long everyDayDelay = 24*60*60*1000;
//first time to execute, it can be your special date
//for example 5 seconds after launch
long timeToExecute = System.currentTimeMillis()+5*1000;
service.scheduleWithFixedDelay(new Task(), getTimeToLaunch(timeToExecute), everyDayDelay, TimeUnit.MILLISECONDS);
where
//return difference between now and timeToExecute
public static long getTimeToLaunch(long timeToExecute){
long current = System.currentTimeMillis();
return timeToExecute - current;
}
class Task implements Runnable{
#Override
public void run() {
System.out.println("Run task!");
}
}
UPDATE: Class to execute your sql-tasks
public class SqlExecutionService1 {
public static final long everyDayDelay = 24*60*60*1000;
public SqlExecutionService1(){
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
//every day to execute
//first time to execute
//for example 5 seconds after launch
long timeToExecute = System.currentTimeMillis()+5*1000;
service.scheduleWithFixedDelay(new SqlTask1(), getTimeToLaunch(timeToExecute), everyDayDelay, TimeUnit.MILLISECONDS);
}
private long getTimeToLaunch(long timeToExecute){
long current = System.currentTimeMillis();
return timeToExecute - current;
}
}
class SqlTask1 implements Runnable{
#Override
public void run() {
//your sql tasks
}
}
To create this class, when your app server starts - use method init() in one of your main servlets.
Example -
public class MainInitServlet extends HttpServlet {
public void init() {
new SqlExecutionService1();
}
}
The Data of a Database should be the basis for calculation, not the result of calculations. In example Bills wont ever be successfully revised.
I guess this fact will ever be a clash between Programmers and Architects.
you might also use the event scheduling mechanism of mysql
this depends on the version of mysql and whether it is enabled or not
is there any thing like alarm manager in Java or mysql that can run all the time in background and trigger # specific time.
look at a API called Quartz , where your program can schedule Jobs and it will run it at that time.
use method execute(JobExecutionContext jobExecution) use to fire trigger.
EG:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
// Retrieve scheduler
Scheduler scheduler = null;
try {
scheduler = schedulerFactory.getScheduler();
}
catch (SchedulerException e) {
e.printStackTrace();
}
//this is a job
JobDetail job = new JobDetail("jobDetail", "jobDetailGroup", ImplementedJob.class);
SimpleTrigger trigger = new SimpleTrigger("Trigger Name","defaultGroup", DATE);
// schedule
scheduler.scheduleJob(job, trigger);
// start the scheduler
scheduler.start();

Categories