Scheduling multiple jobs with dynamic parameter using Quartz 1.6.2 (simple trigger) + Spring 3.0 - quartz-scheduler

I am trying to create a sample scheduler program using quartz simple trigger. My objective is run a single method with different parameters passed dynamically by user (considered as new Job)and schedule it for user defined time which is also received dynamically.
eg:
public void printMe (String name, int Age, Date dob) {
system.out.println("Name:"+name+" Age:"+age+" DOB:"+dob);
}
How to schedule and execute this method based on dynamically received parameters and start date and time using quartz 1.6.2. I am new to quartz scheduler, I have no idea how to do this. Do anyone help me with the sample programs you have?

Here is example to use quartz job via simple trigger
Simple Trigger 1 minutes with 1 second delay for every run to execute:
public static void main(String[] args) throws Exception{
JobDetail job = new JobDetail();
job.setName("dummyJobName");
job.setJobClass(HelloJob.class);
//configure the scheduler time
SimpleTrigger trigger = new SimpleTrigger();
trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(100000);// set time run again is 1 minutes
//schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
You create class for execute class job
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job
{
public void execute(JobExecutionContext context)
throws JobExecutionException {
printmMe("YourName",20,"12/15/2013");
}
public void printMe (String name, int Age, Date dob) {
system.out.println("Name:"+name+" Age:"+age+" DOB:"+dob);
}
}
Above, that's program use quartz schedule to execute job HellloClass

Related

How to stop or cancel a running scheduled task?

I have a Task Scheduler running in my Micronaut Application as described here. What I want is an option to shutdown this task if I receive some kind of request from the user. How can I do that?
In order to cancel a scheduled task you need to work directly with the TaskScheduler.
The following example explains cancelling of a job.
#Singleton
public class SomeBeanThatDoesScheduling {
private final TaskScheduler taskScheduler;
private ScheduledFuture<?> scheduledFuture;
public SomeBeanThatDoesScheduling(#Named(TaskExecutors.SCHEDULED) TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
// on application startup you can register your scheduled task
#EventListener
public void onStartup(StartupEvent startupEvent) {
scheduledFuture = taskScheduler.scheduleWithFixedDelay(initialDelay, interval, this::execute);
}
public void execute() {
System.out.println("The task has been executed");
}
// use this method to cancel the job
public void cancelTheJob() {
if (this.scheduledFuture != null) {
this.scheduledFuture.cancel(false);
}
}
}

How to prevent spring batch to start new instance of job?

Idea is not to start job if already same job is running.
JobExplorer is simple injected in class where is scheduled method for running
public class JobClass {
private final Job job;
private final JobExplorer jobExplorer;
private final JobLauncher jobLauncher;
public JobMain(Job job,
JobLauncher jobLauncher,
JobExplorer jobExplorer) {
this.job = job;
this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer;
}
and then it is executed
#Scheduled("0 */5 * ? * *")
public void startJob() {
JobParameters jobParameters = new JobParametersBuilder()
.addString("jobName", String.valueOf(instant.toEpochMilli()))
.toJobParameters();
jobLauncher.run(job, jobParameters);
}
This is not solution because if JVM stopped while job is running this will be same as current job running:
jobExplorer.findRunningJobExecutions("jobName")
It will find all jobs with exitCode ExitStatus.UNKNOWN.
There is 3 solutions as I see it:
Solution 1:
stop previous running not finished jobs and run new job
PROS: everything is clean, just one property
CONT: loosing current execution of current job
#Scheduled("0 */5 * ? * *")
public void startJob() {
(JobExecution jobExecution: jobExplorer.findRunningJobExecutions("jobName")) jobExecution.stop();
...
}
Solution 2
Calculate time between latest running job like it is here described and if it is any do not start new job:
https://stackoverflow.com/a/23218986/1182625
PROS: everything is clean
CONT: have to have doubled property (5 *60*1000 and "0 */5 * ? * *")
Set<JobExecution> jobExecutions = jobExplorer.findRunningJobExecutions("jobName");
if(jobExecutions.size()>1){
Long currentTime = (new Date()).getTime();
for(JobExecution execution : jobExecutions) {
if((currentTime - execution.getStartTime().getTime()) < 5*60*1000) {
return;
} else {
execution.stop();
}
}
}
Solution 3
Idea is simple to add static (to share between instances of class) volatile (to share between threads) flag which will indicate is any job currently running
PROS: just one property
CONT: needs 2 listeners, and volatile static variable which i don't know how reacted in multi-nodes environment
private static volatile boolean FINISHED = true;
and then simple add listener and FINISHED modify method:
// reset FINISHED after job is done
#AfterJob
public void afterJob() {
FINISHED = true;
}
public void setFinished() {
this.FINISHED = true;
}
And simple add:
#Scheduled("0 */5 * ? * *")
public void startJob() {
if(!FINISHED) return;
FINISHED = false;
...
}
And finally add StepListener
public MyStepListener() {
...
#AfterStep
public ExitStatus afterStep(StepExecution stepExecution) {
if(stepExecution.getExitStatus().getExitCode().equalsIgnoreCase(ExitStatus.FAILED.getExitCode())) (new JobMain()).setFinished();
return null;
}
Ok, I think I go to far with something could be KISS.
Keep It Simple & Stupid.
So, to achieve this is simple to put fixedDelay or fixedStringDelay in #Scheduled annotation if you want to use value from properties file.
#Scheduled(initialDelay = 3*60*1000, fixedDelayString ="${job.fixed_delay}")
With this I achieve that I don't have more than 1 instance of same job at same time.
I only lose that job start at exactly time (like ad midnight or...)
Idea is not to start job if already same job is running.
By design, Spring Batch will prevent that. If you try to start the same job instance while it has a running job execution, you will get a JobExecutionAlreadyRunningException.

Eclipse job with UI access

I have one situation.
I have one Eclipse job with following code:
private class ExecutionJob extends Job {
public static final String MY_FAMILY = "myJobFamily";
public ExecutionJob(String name) {
super(name);
}
#Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("executing ...... ", IProgressMonitor.UNKNOWN);
methodForExecution();
monitor.done();
return Status.OK_STATUS;
}
#Override
public boolean belongsTo(Object family) {
return family == MY_FAMILY;
}
}
And this methodForExecution() has code as below :
public void methodForExecution(){
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("view_id");
}
Now, the situation is, job opens up something like progressmonitor, and my method is trying to access UI which is actually behind this job's progressmonitor. And it gives NullPointerException as the progress monitor does not have ActiveWorkbenchWindow.
I can not use UIJob, as I have to execute this methodForExecution() asynchronously.
Can someone please help me resolving this.
The code you want to run must run in the UI thead.
If most of the work in the job is updating the UI and there is no long running non-UI code then you should use UIJob to run this. This is still scheduled as a job but the runInUIThread method is executed in the UI thread.
If you have a lot of non-UI code especially long running code then use a normal Job but you will have to use Display.asyncExec to run the method in the UI thread:
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
methodForExecution();
}
});
In Java 8 you could do:
Display.getDefault().asyncExec(this::methodForExecution);
You can also use syncExec instead of asyncExec to wait for the UI to update.
If the showView is all you want to do you could just do the asyncExec without using a Job.

Creating an Esper long running process or service

I'd like to create an Esper engine long running process but I'm not sure of Esper's threading model nor the model I should implement to do this. Naively I tried the following:
public class EsperTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
EPServiceProvider epService = EPServiceProviderManager.getProvider("CoreEngine");
epService.addServiceStateListener(new EPServiceStateListener() {
#Override
public void onEPServiceDestroyRequested(EPServiceProvider epsp) {
System.out.println("Service destroyed");
}
#Override
public void onEPServiceInitialized(EPServiceProvider epsp) {
System.out.println("System initialised");
}
});
epService.initialize();
}
}
But the code appears to execute to the end of the main() method and the JVM ends.
Referring to the Esper documentation, section 14.7 p456:
In the default configuration, each engine instance maintains a single timer thread (internal timer)
providing for time or schedule-based processing within the engine. The default resolution at which
the internal timer operates is 100 milliseconds. The internal timer thread can be disabled and
applications can instead send external time events to an engine instance to perform timer or
scheduled processing at the resolution required by an application.
Consequently I thought that by creating a an engine instance ("CoreEngine") at least one (timer) thread would be created and assuming this is not a daemon thread the main() method would not complete but this appears not to be the case.
Do I have to implement my own infinite loop in main() or is there a configuration which can be provided to Esper which will allow it to run 'forever.?
The timer threads is a daemon thread.
Instead of a loop use a latch like this.
final CountDownLatch shutdownLatch = new CountDownLatch(1);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
shutdownLatch.countDown();
}
});
shutdownLatch.await();

Is it possible to kill a current running Quartz Job?

I remember that we cannot kill the current running Quartz Job but we can interrupt and have a boolean check wherever is necessary whether we need to proceed further with the subsequent operations or not.
Even when we implement the InterruptableJob and call the scheduler.interrupt to interrupt the Job, the current executed job will be still running in the server.
Ex:
A named SQL query has been triggered by the job via Hibernate which takes a long time
A call has been made to a third party server where the third party server takes a long time to respond
http://neopatel.blogspot.in/2011/05/quartz-stop-job.html
http://forums.terracotta.org/forums/posts/list/3191.page
Could someone corrects my understanding and explain me how we can kill or stop the "currently" executing Job ?
you can create new abstract class called JobBase for example that implements IJob interface and insert abstract method:
public abstract void ExecuteJob(IJobExecutionContext context);
On JobBase you can implements method Execute like this
public abstract class JobBase : IJob,IInterruptableJob
{
private Thread currentThread;
private ILog logger;
public JobBase(ILog logger)
{
this.logger=logger;
}
public void Execute(IJobExecutionContext context)
{
var thread = new Thread(()=>
{
try
{
this.ExecuteJob(context);
}
catch(Exception ex)
{
this.logger.ErrorFormat("Unhandled exception {0}",ex.ToString());
}
});
thread.Start();
this.currentThread = thread;
this.currentThread.Join();
}
public abstract void ExecuteJob(IJobExecutionContext context);
public void Interrupt()
{
currentThread.Abort();
}
}
Each Job will implements JobExecute method.
public class TestJob :JobBase
{
private ILog logger;
public TeJob(ILog logger):base(logger)
{
}
public override ExecuteJob(IJobExecutionContext context)
{
}
}
Assumes that use some factory for creating a Job
For Stopping a Job you will call method scheduler.Interrupt(new JobKey(jobName));
As you told, there is no way to interrupt "brutally" a job in quartz, neither in JAVA.
You can encapsulate your job's logic in a separate Thread and run it with the ExecutorService.
Take a look to this example: https://stackoverflow.com/a/2275596/1517816
Assume your QuartzJob is the Test class and move your business logic in the Task class.
Hope it helps
I don't know why nobody mentioned this, or maybe this was not available at the time the question was asked.
There is a method called shutdown for a Scheduler instance.
SchedulerFactory factory = new StdSchedulerFactor();
Scheduler scheduler = factory.getScheduler();
The above is used to start a job like
scheduler.start();
Use a flag or something to know when to stop the job from running. Then use
scheduler.shutdown();
How I implemented my requirement:
if(flag==true)
{
scheduler.start();
scheduler.scheduleJob(jobDetail, simpleTrigger);
}
else if(flag==false)
{
scheduler.shutdown();
}
Where jobDetail and simpleTrigger are self explanatory.
Hope it helps. :)