Quartz是由三個元件:Scheduler、Trigger和Job組成,一個Job可被多個Trigger使用,一個Trigger可以觸發多個Job,這而實際都是由Scheduler去執行Job的內容。本案是使用賽門奧客的Veritas進行software的failover,因此當failover一切過去,可能未執行、執行中或執行畢的Job都有遇到不同的狀況,因為Vertias是使用Linux上的kill -9指令中止process的。好在Listener的機制這時可以派上用場。Listener也依Quartz三個核心元件而分別對映到這三個Listener,目前以JobListener作飯粒:
(FooJobListener.java)
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
public class FooJobListener implements JobListener {
public void jobExecutionVetoed(JobExecutionContext context) {
// 被Trigger所阻, Job無法執行
}
public void jobToBeExecuted(JobExecutionContext context) {
// Job執行前
}
public void jobWasExecuted(JobExecutionContext context, JobExecutionException exception) {
// Job執行後, 失敗的話exception會有值
}
public FooJobListener() {
// 初始化, 在failover切過來後, Quartz被執行可喚起
}
}
假設Foo這個Job預定12點在A機執行,但在12:05就被切換到B機,而這時的A機的Foo Job尚未完成,也就是還沒執行到jobWasExecuted method。若要恢復執行前的狀態,即jobToBeExecuted method的內容,這時failover一切過去時,JobListener的建構子內容可以是jobToBeExecuted method的內容,馬上就被執行,不用苦俟到下一個12點去call jobToBeExecuted method來reset。
而在Scheduler註冊方式如下:
Scheduler scheduler = (new StdSchedulerFactory()).getScheduler();
job = new JobDetail(...); // 引數略
JobListener jobListener = new FooJobListener();
scheduler.addJobListener(jobListener);
job.addJobListener(jobListener.getName()); // Job的addJobListener必須是Listener的name string,如此才會匹配到對映的Job
Trigger trigger = new CronTrigger(...); // 引數略
scheduler.scheduleJob(job, trigger);
scheduler.start();
若希望這個Listener通用於所有Job,則用scheduler.addGlobalJobListener(jobListener)取代以上劃有底線的兩行。
另外兩個Listener的method也加以說明:
public void triggerFired(Trigger trigger, JobExecutionContext context); // Job 上的 execute() 方法即將被執行時
public boolean vetoJobExecution(Trigger trigger, JobExecutidonContext context); // 返回false則表示這個Listener拒絕執行job
public void triggerMisfired(Trigger trigger); // 這比較特殊,如預計12點執行時恰巧shutdown, 重開機已1點, 錯過這個時間沒執行Job就會呼叫這個method
public void triggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode); // 執行完成。
和JobListener,也有addGlobalTriggerListener用法。而SchedulerListener的介面,看原始定義大概就能望文生義了。
public interface SchedulerListener {
public void jobScheduled(Trigger trigger);
public void jobUnscheduled(String triggerName, String triggerGroup);
public void triggerFinalized(Trigger trigger);
public void triggersPaused(String triggerName, String triggerGroup);
public void triggersResumed(String triggerName,String triggerGroup);
public void jobsPaused(String jobName, String jobGroup);
public void jobsResumed(String jobName, String jobGroup);
public void schedulerError(String msg, SchedulerException cause);
public void schedulerShutdown();
}