Quartz
Quartz ist ein Framework, mit dem man zeitgesteuert Code ausführen lassen kann.
Quartz Logging
Quartz nutzt . Zum Start slf4j-api-?.jar und slf4j-simple-?.jar in den Klassenpfad aufnehmen. Letzteres kann man dann z.B. durch slf4j-log4j12-?.jar ersetzen, wenn man lieber log4j benutzen möchte.
quartz.properties
org.quartz.scheduler.instanceName = MyScheduler
# Max Number of parallel threads
org.quartz.threadPool.threadCount = 5
# store jobs in RAM instead of a real DB
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Quartz Beispiele
Quartz Job:
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MySimpleJob implements Job
{
@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
...
}
}
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.TriggerBuilder.*;
public class Main
{
...
// Grab the Scheduler instance from the Factory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// and start it off
scheduler.start();
// the job shall be started 8 times
JobDetail job = newJob(MySimpleJob.class).withIdentity("job1", "group1").build();
SimpleScheduleBuilder sb=SimpleScheduleBuilder.repeatSecondlyForTotalCount(8);
// Trigger the job to run now, and then repeat every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(sb)
.build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
// give the processes time to finish
Thread.sleep(5*60*1000);
scheduler.shutdown();
...
}
JobDataMap
Man kann den neu angelegten Jobs noch Werte über eine eingebaute Map mitgeben. Diese Map wird bei Bedarf sogar mit dem Job zusammen persistiert (wenn die Werte serialisierbar sind).
.withIdentity("job1", "group1")
.usingJobData("MY_MESSAGE", "Hello World")
.build();
Und so können die Werte im Job dann wieder ausgelesen werden
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
JobDataMap dataMap=jobexecutioncontext.getJobDetail().getJobDataMap();
String lMessage=dataMap.getString("MY_MESSAGE");
}
Falls es im Job Objekt Setter gibt, die wie ein Key aus der Map heißen, werden diese auch aufgerufen. z.B.
Quartz Annotation
Der Job, der so annotiert wurde, darf nicht parallel zu einem anderen Job mit der gleichen Klasse laufen
Quartz Cron
* Quartz Cron syntax
*
* Seconds Minutes Hours Day-of-Month Month Day-of-Week Year(optional)
*
* Day-of-Weeks:
* MON
* TUE
* WED
* THU
* FRI
* SAT
* SUN
* MON-FRI
* MON,WED,FRI
* MON-WED,SAT
* * (every day in the week)
* ? day of the week is not relevant
*
* Day-of-Month
* 1 first day in month
* L last day in month
* * any day in month
* ? day in month is not relevant
*
*/
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// and start it off
scheduler.start();
JobDetail job1 = newJob(MySimpleJob.class)
.withIdentity("job1", "group1")
.build();
// Noon
String cronString_noon="0 0 12 ? * *";
// Noon on Wednesday
String cronString_noon_wednesday="0 0 12 ? * WED";
// Every 6 minutes of the hour (10:06, 10:12, ..., 10:54, 11:06, etc)
String cronString_every_6="0 0/6 * * * ?";
// Every 35 minute of the hour (10:35, 11:35, 12:35, etc)
String cronString_every_35="0 0/35 * * * ?";
Trigger trigger_noon = newTrigger()
.withIdentity("trigger_noon", "group1")
.withSchedule(cronSchedule(cronString_noon))
.build();
Trigger trigger_noon_wednesday = newTrigger()
.withIdentity("trigger_noon_wednesday", "group1")
.withSchedule(cronSchedule(cronString_noon_wednesday))
.build();
Trigger trigger_every_6 = newTrigger()
.withIdentity("trigger_every_6", "group1")
.withSchedule(cronSchedule(cronString_every_6))
.build();
Trigger trigger_every_35 = newTrigger()
.withIdentity("trigger_every_35", "group1")
.withSchedule(cronSchedule(cronString_every_35))
.build();
// Tell Quartz to schedule the job using our trigger
scheduler.scheduleJob(job1, trigger_noon);
scheduler.scheduleJob(job2, trigger_noon_wednesday);
scheduler.scheduleJob(job3, trigger_every_6);
scheduler.scheduleJob(job4, trigger_every_35);
Listeners
Es gibt
- JobListener
- SchedulerListeners
Job Stores
RAMJobStore
JDBCJobStore
Quartz herunterladen, unter docs/dbTables/ findet man dann für verschiedene DB Scripte um die Tabellen anzulegen, die Quartz für den JDBCJobStore benötigt. Diese Tabellen in der DB anlegen. Man benötigt das c3p0 jar im Klassenpfad und JDBC Treiber für die DB, z.B. ojdbc6.jar für Oracle.
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# Oracle
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myQuartzDataSource
org.quartz.jobStore.useProperties = false
# Configure Datasources
org.quartz.dataSource.myQuartzDataSource.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myQuartzDataSource.URL = jdbc:oracle:thin:@myComputer.example.com:1521:myDB
org.quartz.dataSource.myQuartzDataSource.user = MrFoo
org.quartz.dataSource.myQuartzDataSource.password = SuperSecretPW123
org.quartz.dataSource.myQuartzDataSource.maxConnections = 5
org.quartz.dataSource.myQuartzDataSource.validationQuery=select 0 from dual
misfireThreshold
Wie lange darf ein Job seine Ausführzeit verpassen bis sie als verpasst angesehen wird? Angabe in Milliseconden, Default ist 60.000 (1 Minute)
Quartz Exceptionhandling
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
try
{
...
}
catch(NullPointerException e)
{
JobExecutionException e_new=new JobExecutionException(e);
// permanent error, never try to execute this job again
e_new.setUnscheduleAllTriggers(true);
throw e_new;
}
catch(Exception e)
{
JobExecutionException e_new=new JobExecutionException(e);
// try to execute this job right way
e_new.refireImmediately();
throw e_new;
}
}