I have two processes:
Process 1 - implements runnable and can run forever.
Process 2 - fires at fixed hour and minute of day (i've created a job that run with Quartz).
To warn the process 1 that the other process is running I can use the TriggerListener, but how can I postpone the fire of the second process if the process 1 still doing something?
For example: I need to fire the trigger at 2PM, but this need to be done after 2PM if the process 1 isnt idle.
Here's some sample:
ProcessForever.java
import static org.quartz.CronScheduleBuilder.dailyAtHourAndMinute;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
public class ProcessForever implements Runnable {
private boolean processTwoRunning;
private Scheduler scheduler;
private Trigger trgProcessTwo;
private String status;
public static final STATUS_PROCESS = "PROCESS";
public static final STATUS_SLEEP = "SLEEP";
private static Logger LOGGER = Logger.getLogger( ProcessForever.class.getName() );
public void init() throws SchedulerException {
SchedulerFactory fact = new StdSchedulerFactory();
scheduler = fact.getScheduler();
}
#Override
public void run() {
try {
scheduler.start();
buildTrigger();
while( true ) {
//do something and then sleep for some time.
//the Quartz trigger should fire only in STATUS_SLEEP...
setStatus( STATUS_PROCESS );
try { Thread.sleep(120 * 1000); }catch(Exception e){}
setStatus( STATUS_SLEEP );
}catch( Exception e ) {
e.printStackTrace();
}
}
private void buildTrigger() throws SchedulerException {
LOGGER.info("defineCargaDadosTrigger()");
JobDetail dt = newJob( ProcessTwo.class )
.withIdentity("coleta","grpcoleta")
.build();
trgProcessTwo = newTrigger().withIdentity(
new TriggerKey("triggerProcessTwo") )
.forJob( dt )
.startNow()
.withSchedule( dailyAtHourAndMinute(13,31) )
.build();
KeyMatcher<TriggerKey> m = KeyMatcher.keyEquals( trgProcessTwo.getKey() );
scheduler.scheduleJob(dt, trgProcessTwo );
//this will notice the process 1 that the trigger is running...
//scheduler.getListenerManager().addTriggerListener(someclass, m );
}
//getters & setters ommited...
}
ProcessTwo.java
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
ProcessTwo cannot run concurrent with ProcessForever...
*/
public ProcessTwo implements Job {
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("Doing something...");
try { Thread.sleep(10000); } catch( InterruptedException i ){}
System.out.println("Stop doing something...");
}
}
That's quite a common question in Quartz. Here are some hints provided by the FAQ
Related
This is a job scheduler code
JobDetail job = JobBuilder.newJob()
.ofType( AppJob.class )
.withIdentity("id", "jobgroup")
.setJobData(jobDataMap)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger_id", "jobGroup")
.startAt( start.getTime() )
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1).repeatForever())
.endAt( end.getTime() )
.build();
And the listener
scheduler.getListenerManager().addJobListener(new JobListener() {
#Override
public String getName() {
return "ffdfd";
}
#Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
}
#Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
}
#Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println(" fdfnkdfkndfnkldnnl OVERRR ");
}
}, KeyMatcher.keyEquals(jobKey(String.valueOf(id), "jobGroup")));
As this is the repeated event, the jobWasExecuted method executes every time for the repeat interval
How to get one final complete event for this job
I have a tiny problem that I can't seem to do right. I have the following class in java:
package pooledtcpconnector.utilities;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class Notifier implements Runnable {
private final ILogger logger;
private Timer mTimer;
private final int Treshold;
private final InputStream ResponseStream;
private final TimerTask DoWaitTask;
public Notifier(final InputStream _ResponseStream, final Integer _Treshold, final ILogger logger) {
this.logger = logger;
mTimer = new Timer();
this.ResponseStream = _ResponseStream;
this.Treshold = _Treshold;
DoWaitTask = new TimerTask() {
#Override
public void run() {
try {
int mSize = ResponseStream.available();
if (mSize >= Treshold) {
mTimer.cancel();
}
} catch (final IOException ex) {
final String ExceptionMessage = ex.getMessage();
logger.LogMessage(
this.getClass().getCanonicalName(),
"Notifier.DoWaitTask:run.ResponseStream.available",
ex.getClass().getCanonicalName(),
new String[]{
ExceptionMessage,
"Parameters:",
String.format("-"),
});
Logger.getLogger(Notifier.class.getCanonicalName()).log(Level.FINE, ex.getMessage(), ex.getCause());
}
}
};
}
#Override
public void run() {
synchronized (this) {
mTimer.scheduleAtFixedRate(DoWaitTask, 250, 200);
// Notification mechanism
notify();
}
}
}
This class would ensure that our application won't start processing the SocketInputStream unless the available method returns at least Treshold. The problem however is that, once I schedule the DoWaitTask with the Timer it runs for eternity. By cancelling the timer the task still runs and the whole application hangs, but more importantly it tries to call available on the stream once it already has been processed and closed. Of course this results in a nice IOException: stream closed.
How could I stop the scheduled task along with the timer? timer.cancel obviously isn't enough.
Regards,
Joey
Use TimerTask.cancel() from within your timer task's run() method. According to the Javadoc for this method:
Note that calling this method from within the run method of a
repeating timer task absolutely guarantees that the timer task will
not run again.
private Timer reportTimer = null;
if (reportTimer != null) {
reportTimer.cancel();
reportTimer = null;
}
reportTimer = new Timer();
reportTimer.schedule(new TimerTask() {}
Edit: I am using quartz-2.1.5.jar. Here's the summary of my classes:
HttpPollingJob extends PollingJob extends ScheduledJob implements org.quartz.Job
Specifically:
1) ScheduledJob implements Quartz Job (abstract base class for all my Job types):
import org.quartz.Job;
import org.quartz.Trigger;
public abstract class ScheduledJob implements Job {
private Trigger trigger;
public ScheduledJob() {
this(null);
}
public ScheduledJob(Trigger trig) {
super();
if(trig == null)
trig = getDefaultTrigger();
setTrigger(trig);
}
public Trigger getTrigger() {
return trigger;
}
public void setTrigger(final Trigger trig) {
trigger = trig;
}
protected abstract Trigger getDefaultTrigger();
}
2) PollingJob extends ScheduledJob - all "pollers" poll some resource/endpoint with a specific frequency:
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import com.me.jobs.ScheduledJob;
public abstract class PollingJob extends ScheduledJob {
private static long DEF_FREQUENCY = 10 * 1000; // 10 secs
private String name;
private long frequency;
public PollingJob(final String nm) {
this(nm, DEF_FREQUENCY);
}
public PollingJob(final String nm, final long freq) {
super();
setName(nm);
setFrequency(freq);
}
public abstract void poll(JobExecutionContext context);
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
poll(context);
}
public String getName() {
return name;
}
public void setName(final String nm) {
name = nm;
}
public long getFrequency() {
return frequency;
}
public void setFrequency(final long freq) {
frequency = freq;
}
protected final Trigger getDefaultTrigger() {
TriggerBuilder<?> triggerBuilder = TriggerBuilder.newTrigger()
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY));
return triggerBuilder.build();
}
}
3) HttpPollingJob extends PollingJob - "HTTP pollers" poll a web server (using HTtpClient):
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.quartz.JobExecutionContext;
import com.me.MonitoredEvent;
import com.me.MonitoredEventRegistrar;
public class HttpPollingJob extends PollingJob {
private String serverURL;
private org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(HttpPollingJob.class);
public HttpPollingJob(final String nm, final String server) {
super(nm);
setServerURL(server);
}
public String getServerURL() {
return serverURL;
}
public void setServerURL(final String server) {
serverURL = server;
}
#Override
public final void poll(JobExecutionContext context) {
MonitoredEvent event = null;
try {
// This is where we would use HttpClient to connect to a web server and poll it.
System.out.println("Job fired!");
}
catch(Throwable thrown) {
logger.error(thrown.getMessage());
}
}
}
4) JobDriver - defines several HttpPollingJobs and uses Quartz to start them:
public class JobDriver {
private List<HttpPollingJob> jobs;
public JobDriver() {
HttpPollingJob job1 = new HttpPollingJob("job-1", "http://www.example.com/1");
HttpPollingJob job2 = new HttpPollingJob("job-2", "http://www.example.com/2");
HttpPollingJob job3 = new HttpPollingJob("job-3", "http://www.example.com/3");
jobs = new ArrayList<HttpPollingJob>();
jobs.add(job1);
jobs.add(job2);
jobs.add(job3);
}
public static void main(String[] args) {
JobDriver driver = new JobDriver();
driver.startJobs();
}
private void startJobs() {
try {
// Obtain a basic SchedulerFactory and fire it up.
SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// Define a job for every declared monitor.
JobBuilder jobBuilder = null;
for(ScheduledJob job : jobs) {
Trigger trigger = job.getTrigger();
jobBuilder = JobBuilder.newJob(job.getClass());
// Bind the current job to this trigger.
scheduler.scheduleJob(jobBuilder.build(), trigger);
// TODO: Shut the scheduler down politely?!?!
}
catch(Throwable exc) {
logger.error(exc.getMessage());
// Force application to kick out.
throw new RuntimeException(exc);
}
}
}
When I run this code I get a perfect startup with no errors or runtime exceptions. If I sprinkle System.out.println statements I can see every single line of code executing flawlessly. The only problem is, once the program is running, its not printing the "Job fired!" message indicating that the polling job is kicking off.
I've tried every combination of start() and shutdown() I can think of to no avail. Can any Quartz mavens look at this code and tell me why the job isn't firing?
In the logs (I configured log4j) I see the Quartz worker thread being created for the scheduled job. I feel like I'm 99% of the way there but am just missing something obvious. Thanks in advance!
#4herpsand7derpsago yes you are right, you are 99% there, I ran your code and there is only one problem in it, the Default constructors are absent in HttpPollingJob and PollingJob classes, For that reason Scheduler is not able to create their instances,
Simple Solution add following code in below classes
HttpPollingJob class
public HttpPollingJob() {
}
PollingJob class
public PollingJob() {
}
Bingo, the following messages will be printed
Job fired!
Job fired!
Job fired!
If you want to repeat the trigger, add following code in PollingJob
protected final Trigger getDefaultTrigger() {
TriggerBuilder<?> triggerBuilder = TriggerBuilder
.newTrigger()
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY).repeatForever());
return triggerBuilder.build();
}
Hoping that now I will receive the bounty :)
BONUS
Seems like you want to poll or do something with urls, A better way to pass that using king JobDataMap
Updated JobDriver
import java.util.ArrayList;
import java.util.List;
import org.quartz.JobBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
public class JobDriver {
private List<HttpPollingJob> jobs;
public JobDriver() {
HttpPollingJob job1 = new HttpPollingJob("job-1",
"http://www.example.com/1");
HttpPollingJob job2 = new HttpPollingJob("job-2",
"http://www.example.com/2");
HttpPollingJob job3 = new HttpPollingJob("job-3",
"http://www.example.com/3");
jobs = new ArrayList<HttpPollingJob>();
jobs.add(job1);
jobs.add(job2);
jobs.add(job3);
}
public static void main(String[] args) {
JobDriver driver = new JobDriver();
driver.startJobs();
}
private void startJobs() {
try {
// Obtain a basic SchedulerFactory and fire it up.
SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// Define a job for every declared monitor.
JobBuilder jobBuilder = null;
for (HttpPollingJob job : jobs) {
Trigger trigger = job.getTrigger();
jobBuilder = JobBuilder.newJob(job.getClass());
jobBuilder.usingJobData("name", job.getName());
jobBuilder.usingJobData("url", job.getServerURL());
// Bind the current job to this trigger.
scheduler.scheduleJob(jobBuilder.build(), trigger);
// TODO: Shut the scheduler down politely?!?!
}
} catch (Throwable exc) {
// Force application to kick out.
throw new RuntimeException(exc);
}
}
}
updated HttpPollingJob
import java.util.Map;
import org.quartz.JobExecutionContext;
public class HttpPollingJob extends PollingJob {
private String serverURL;
private org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(HttpPollingJob.class);
public HttpPollingJob(final String nm, final String server) {
super(nm);
setServerURL(server);
}
public HttpPollingJob() {
}
public String getServerURL() {
return serverURL;
}
public void setServerURL(final String server) {
serverURL = server;
}
#Override
public final void poll(JobExecutionContext context) {
try {
Map dataMap = context.getJobDetail().getJobDataMap();
String nm = (String)dataMap.get("name");
String url = (String)dataMap.get("url");
// This is where we would use HttpClient to connect to a web server and poll it.
System.out.println("Job fired! name:"+nm+" url:"+url);
}
catch(Throwable thrown) {
logger.error(thrown.getMessage());
}
}
}
new output
Job fired! name:job-1 url:http://www.example.com/1
Job fired! name:job-2 url:http://www.example.com/2
Job fired! name:job-3 url:http://www.example.com/3
Apparently, you have not started the trigger. See Quartz Tutorial or Javadocs:
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
Its your constructors - the JobBuilder looks for the no-args and since they're not defined it refuses to build the jobs. Add empty no-arg ctors and you're all set.
Could you try to change the code of the method getDefaultTrigger in the class PollingJob into the following :
protected final Trigger getDefaultTrigger() {
return TriggerBuilder.newTrigger()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY))
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.build();
}
i feel some issue with the way you create the trigger.
Remember you cannot reuse trigger for multiple jobs
Try creating trigger with unique identity and group like below
Trigger everyHourTrigger = newTrigger().withIdentity("everyWeeklyTrigger", "group1")
.startNow().withSchedule(cronSchedule("0 1 * * * ?")).build();
I'm using Quartz to write a simple server monitor in Java:
public class ServerMonitorJob implements Job {
#Override
public void execute(JobExecutionContext ctx) {
// Omitted here for brevity, but uses HttpClient to connect
// to a server and examine the response's status code.
}
}
public class ServerMonitorApp {
private ServerMonitorJob job;
public ServerMonitorApp(ServerMonitorJob jb) {
super();
this.job = jb;
}
public static void main(String[] args) {
ServerMonitorApp app = new ServerMonitorApp(new ServerMonitorJob());
app.configAndRun();
}
public void configAndRun() {
// I simply want the ServerMonitorJob to kick off once
// every 15 minutes, and can't figure out how to configure
// Quartz to do this...
// My initial attempt...
SchedulerFactory fact = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = fact.getScheduler();
scheduler.start();
CronTigger cronTrigger = new CronTriggerImpl();
JobDetail detail = new Job(job.getClass()); // ???
scheduler.schedule(detail, cronTrigger);
scheduler.shutdown();
}
}
I think I'm somewhere around the 70% mark; I just need help connecting the dots to get me all the way there. Thanks in advance!
You are almost there:
JobBuilder job = newJob(ServerMonitorJob.class);
TriggerBuilder trigger = newTrigger()
.withSchedule(
simpleSchedule()
.withIntervalInMinutes(15)
);
scheduler.scheduleJob(job.build(), trigger.build());
Check out the documentation, note that you don't need a CRON trigger when you simply want to run the job every 15 minutes.
I am using JBoss5.1.x AS, EJB3.0. I am trying to add a job (using Quartz) to my deployment. I am registering a new Service, so it will init the scheduler on application deploy.
My problem is that the service never gets registered when I deploy my app.
My code:
Interface:
public interface ComponentMonitoringService
{
void create() throws Exception;
void start() throws Exception;
void stop();
void destroy();
}
Service:
#Service(objectName = "com.mirs.ecms.timer:service=ServerStartupManager")
#Management(ComponentMonitoringService.class)
public class ServerStartupManager implements ComponentMonitoringService
{
private SchedulerFactory schedulerFactory = null;
private Scheduler scheduler = null;
Logger logger = Logger.getLogger("ecms.log");
public void create() throws Exception
{
}
public void start() throws Exception
{
// Write your startup code
initScheduler();
}
private void initScheduler() throws ParseException, SchedulerException
{
schedulerFactory = new StdSchedulerFactory();
scheduler = schedulerFactory.getScheduler();
JobDetail startECMSJob = new JobDetail("startECMSJob", "group1", StartECMSJob.class);
CronTrigger trigger1 = new CronTrigger("cronTrigger", "TriggersGroup1", "0 0/5 * * * ?");
scheduler.scheduleJob(startECMSJob, trigger1);
scheduler.start();
}
public void stop()
{
try
{
scheduler.shutdown();
}
catch (Exception e)
{
logger.error("ServerStartupManager Failure occured during Manager stop", e);
}
}
public void destroy()
{
}
}
I found a solution.
I was not using the right annotation. I have to use EJB3 annotations.