顯示具有 quartz 標籤的文章。 顯示所有文章
顯示具有 quartz 標籤的文章。 顯示所有文章

2013年11月12日 星期二

Quartz - 出現org.quartz.SchedulerException: Problem instantiating class...


問題:出現org.quartz.SchedulerException: Problem instantiating class 導致JOB無法順利被初始化執行


請檢查Job Class是否有實做default construction

2013年5月19日 星期日

Quartz初體驗 - 如何關閉煩人的console output 改用 file方式記錄?


(以quartz 2.1.6為例)

  1. 所需lib:quartz-all-2.1.6.jar、slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.1.jar、log4j-1.2.16.jar、c3p0-0.9.1.1.jar (直接至quartz官方網站就可下載)
  2. 創建檔案 log4j.properties,內容如下:
    # Root logger option
    log4j.rootLogger=INFO, file
     
    # Direct log messages to a log file
    log4j.appender.file=org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=C:\\loging.log
    log4j.appender.file.MaxFileSize=1MB
    log4j.appender.file.MaxBackupIndex=1
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    org.quartz.logger.schedLogger.class = org.quartz.impl.Log4jLogger 
    org.quartz.logger.schedLogger.categoryName = scheduler 
    

    log4j.appender.file.File=C:\\loging.log 可自行更改為所需的file outputf路徑
    log4j.rootLogger=INFO, file 自行更改所需的LOG LEVEL,共有:
    TRACE > DEBUG > INFO > WARN > ERROR > FATAL 
  3. 創建檔案 quartz.properties,內容如下:

    org.quartz.scheduler.instanceName = MyScheduler
    org.quartz.threadPool.threadCount = 3
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    org.quartz.logger.schedLogger.class = org.quartz.impl.Log4jLogger 
    
  4. 完成,再下來就是寫CODE囉
記得不要同時置放log4j.xml,否則似乎會以log4j.xml為主

2013年4月6日 星期六

Quartz初體驗 - Jobs and Triggers介紹


  • Schedule:用來掌管所有需要執行的Job,包含呼叫Job execute(...)
  • Job :所需要執行的內容Class都需implements 此 interface
  • JobDetail :用來定義Job instances 
  • JobBuilder :用來建立JobDetail 
  • Trigger :設定實際運作Job的執行細節,例如:執行時間狀態
  • TriggerBuilder :用來建立Trigger 
常用Trigger:
  1. SimpleTrigger
    使用狀況:一次性執行、指定時間執行(可重複N次)、間隔延遲指定時間執行...
  2. CronTrigger
    使用狀況:指定日期執行,例如:每個星期五早上十點執行、每個月的10號下午兩點執行...etc

  • 重點節錄:

When the Job's trigger fires (more on that in a moment), the execute(..) method is invoked by one of the scheduler's worker threads

  • 將Trigger與Job分開建立的優勢:

  1. 可以定義好幾個不同的Trigger(執行時間),卻執行同一Job
  2. 使用JobKey and TriggerKey來管理你的Jobs與triggers,可用來進行分類管理,例如:Log用、維護用...etc

Quartz初體驗 - 如何使用不同的Schedule PropertySetting


在執行
scheduler.scheduleJob(job, trigger);

時出現:


RROR JobRunShell - Job group1.server.client.loginobserver.BackupGpBaseDataObser
ver@6909db threw an unhandled Exception:
java.lang.NullPointerException
        at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.j
ava:557)


後來發現原來呼叫預設的

_scheduler = StdSchedulerFactory.getDefaultScheduler();

等同使用quartz.properties 此設定檔中的資料,
而每一個設定檔中的資料只能使用一次,因此若需建立第二個schedule,則需使用不同的設定檔:
  1. 建立新的properties設定檔:"backup.quartz.properties"
     
    org.quartz.scheduler.instanceName = MyBackupScheduler
    org.quartz.threadPool.threadCount = 3
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    
  2. 將建立schedule code改為:
     
    StdSchedulerFactory factory = new StdSchedulerFactory();
     factory.initialize("backup.quartz.properties");
    _scheduler = factory.getScheduler();
    _scheduler.start();
而原先呼叫 StdSchedulerFactory.getDefaultScheduler() 等同於:
 
StdSchedulerFactory factory = new StdSchedulerFactory();
 factory.initialize();//default use quartz.properties 
_scheduler = factory.getScheduler();
_scheduler.start();

不過我搞不太懂為什麼問題出在【重複Schedule設定】,卻會拋出NullException這種這麼不明確的錯誤呢....
參考:Novice question: how do I get to PropertySettingFactory?

Quartz初體驗 - Job and Job Details



參考下列片段:


 
// define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .build();
        
  // Trigger the job to run now, and then every 40 seconds
  Trigger trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())            
      .build();
        
  // Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);

line 1~3說明了最簡單建立Job的方式,提供簡單的extend Job的Class!Job的建立生命週期如下:

  1. Shedule建立執行Job之前(call job's execute(..)),便為Job建立新的instance(如上述的HelloJob)
  2. Shedule call job's execute(..)
  3. job使用完畢,等待被GC回收
因此由上述可見,我們並無法使用任何有狀態、或需要保存資料的Job,或於Job執行前給予特定資料,因為Job永遠是使用default constuctor建立且於每次execute時重新建立、之後回收。
那麼,我們要怎麼樣在Job被execute之前指定特定資料呢?

使用JobDataMap


1.設定資料:
   
// define the job and tie it to our DumbJob class
  JobDetail job = newJob(DumbJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .usingJobData("jobSays", "Hello World!")
      .usingJobData("myFloatValue", 3.141f)
      .build();

2.取得資料:
 
public class DumbJob implements Job {

    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      JobKey key = context.getJobDetail().getKey();

      JobDataMap dataMap = context.getJobDetail().getJobDataMap();

      String jobSays = dataMap.getString("jobSays");
      float myFloatValue = dataMap.getFloat("myFloatValue");

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }
  }

如上述範例,可先於創立JobDetail時指定資料,後於Job execute()時使用getJobDetail().getJobDataMap();取得所需資料。
然而需注意的是,置放於DataMap()的資料皆需為serialized 

參考:Lesson 3: More About Jobs and Job Details

Quartz初體驗 - 從Job中自行關閉自己


  1. 於public void execute(JobExecutionContext arg0) throws JobExecutionException自行拋出JobExecutionException
  2. 將欲拋出的JobExecutionException設定為setUnscheduleAllTriggers(true)
  3. throw JobExecutionException

 
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
  //do something...
       try {
            int zero = 0;
            int calculation = 4815 / zero;
        } 
        catch (Exception e) {
            _log.info("--- Error in job!");
            JobExecutionException e2 = 
                new JobExecutionException(e);
            // Quartz will automatically unschedule
            // all triggers associated with this job
            // so that it does not run again
            e2.setUnscheduleAllTriggers(true);
            throw e2;
        }
}

參考:Example - Dealing with Job Exceptions