Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quartz Jobs Not Kicking Off

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!

like image 807
IAmYourFaja Avatar asked Jun 26 '12 13:06

IAmYourFaja


2 Answers

@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

like image 71
maaz Avatar answered Oct 25 '22 22:10

maaz


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();
like image 22
Andy Avatar answered Oct 25 '22 23:10

Andy