1. 程式人生 > >使用 QWorker 做為計劃任務引擎

使用 QWorker 做為計劃任務引擎

QWorker 提供了 Plan 函式來提供計劃任務功能的支援。每個任務做為一個作業,可以在指定的時間點被觸發執行。而 cron 作為 Linux 作業系統下計劃任務的標準被廣大使用者所熟知,QWorker 也就不再閉門造車,決定遵從這一規則。但是,可但是,通過百度後,你會發現有兩個,一個是 crontab 標準,精確到分鐘,另一個是 java 的 spring 框架使用的仿 cron 格式,精確到秒。在一翻無謂的掙扎和猶豫之後,最終決定使用 spring 相容的實現,原來基於 cron 的實現被推倒重新實現。

好了,確定了目標並實現之後,我們就是實踐了。計劃任務作業的建立與普通的作業其實並沒有什麼不同,如果非要說有啥不同,那就是計劃任務作業的介面函式名為 Plan,並且使用了一個 TQPlanMask 型別的引數來傳遞計劃任務的排程計劃。

先來看看 Plan 函式的宣告:

 
1 2 3 4 5 6 7 8 function Plan(AProc: TQJobProc; const APlan: TQPlanMask; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload;
function Plan(AProc: TQJobProc; const APlan: QStringW; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload; function Plan(AProc: TQJobProcG; const APlan: TQPlanMask; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload;
function Plan(AProc: TQJobProcG; const APlan: QStringW; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload; {$IFDEF UNICODE} function Plan(AProc: TQJobProcA; const APlan: TQPlanMask; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload; function Plan(AProc: TQJobProcA; const APlan: QStringW; AData: Pointer;ARunInMainThread: Boolean = False;AFreeType: TQJobDataFreeType = jdfFreeByUser): IntPtr; overload; {$ENDIF}

好了,簡單說下幾個引數都幹啥的,AProc、AData、ARunInMainThread、AFreeType 這四個引數與普通的作業並沒有任何不同,依然是作業處理函式、附加資料指標、是否執行在主執行緒、附加資料指標的釋放方式,唯一多出來的引數就是 APlan,從上面的宣告可以看出來,我們提供了兩個過載,一個是 TQPlanMask 型別,另外一個是直接的 QStringW,我們可以根據需要選擇一個格式:

  • TQPlanMask 格式可以提供更多額外的控制,比如計劃任務的首次執行時間範圍。
  • 如果沒有額外的控制需要,QStringW 格式是直接設定作業排程的掩碼,明顯更方便一些。

下面我們看呼叫的一個例子:

 
1 Workers.Plan(DoPlanJob, '0 * * * * * "每分鐘重複一次的作業"', nil, True);

這樣一句程式碼就定義了一個計劃任務,要求在每分鐘執行一次作業 DoPlanJob。為什麼呢,我們就要從這個計劃任務的格式掩碼說起。

QWorker 的計劃任務掩碼參考自 Spring ,共有 6-7 部分組成,格式如下:

秒 分 時 日 月 周 [年]

其中,年是可選,沒有的話,就忽略它的檢查。第一個部分都有自己的取值範圍和為了方便條件設定的萬用字元,年、月、日和時、分、秒我覺得就不用細說取值範圍了,相信你也知道,只是特別說明以下幾點:

  • 小時使用的是  24 小時制,所以範圍是0-23;
  • 月可以使用月份的英文縮寫,如 JAN、MAY 等;
  • 周是以週一為起點,定義為 1 ,剩下的依次類推,也就是說週日為7,當然更清晰的是使用星期的英文縮寫,如 SUN、WED 等;為了和 Linux 的 cron 保持相容,會同時將 0 識別為週日。
  • 年份的表示範圍是 1970~9999,不過這個估計很少用了。
  • 補充一點,月或周使用英文時不區分大小寫,所以 JAN 和 jAn 的結果是一樣一樣的。

然後我們說一下萬用字元。所有的部分都支援 -、* 和 / 三種,日部分還額外支援 L、W 和 ?,周額外支援 L 和 ?。下面說一下各個萬用字元的含義:

  • *
    表示所有值. 例如:在分的欄位上設定 “*”,表示每一分鐘都會觸發;
  • ?
    表示不指定值。使用的場景為不需要關心當前設定這個欄位的值。例如:要在每月的10號觸發一個操作,但不關心是周幾,所以需要周位置的那個欄位設定為“?”,具體設定為 0 0 0 10 * ?;

  • 表示區間。例如 在小時上設定“10-12”,表示 10、11、12 點都會觸發;
  • ,
    表示指定多個值,例如在周欄位上設定 “MON,WED,FRI” 表示週一,週三和週五觸發;
  • /
    用於遞增觸發。如在秒上面設定 “5/15”  表示從 5 秒開始,每增 15 秒觸發(5、20、35、50)。 在月欄位上設定 “1/3” 所示每月 1 號開始,每隔三天觸發一次;
  • L
    表示最後的意思,取英文 Last 的縮寫。在日欄位設定上,表示當月的倒數第幾天(依據當前月份,如果是二月還會依據是否是閏年),如 L-2 代表從月份的最後一天開始倒數兩天,L0 時,0可以省略,代表月份的最後一天。 在周欄位上表示星期六,相當於 “7” 或 “SAT”。如果在 “L” 前加上數字,則表示該月最後一個星期幾。例如在周欄位上設定 “6L” 這樣的格式,則表示 “本月最後一個星期五”;
  • W
    表示離指定日期的最近那個工作日(預設為週一至週五,你可以重新實現一個函式,然後設計 IsWorkDay 函式指標指向它來個性化工作日設定)。例如在日欄位上設定 “15W”,表示離每月 15 號最近的那個工作日觸發。如果 15 號正好是週六,則找最近的週五(14號)觸發,,如果 15 號是周未,則找最近的下週一(16號)觸發。如果15號正好在工作日(週一至週五),則就在該天觸發。如果指定格式為 “1W”,它則表示每月 1 號往後最近的工作日觸發。如果 1 號正是週六,則將在 3 號下週一觸發。(注,”W”前只能設定具體的數字,不允許使用區間 “-”);
  • #
    序號(表示每月的第幾個周幾),例如在周欄位上設定“6#3”,表示在每月的第三個週六。注意如果指定 “n#5”,而正好第五週沒有周六,則不會觸發該配置(用在母親節和父親節再合適不過了) ;

好了,格式的說明也就這樣子了,提示下 L 和 W 可以一起組合使用。如果在日欄位上設定 LW ,則表示在本月的最後一個工作日觸發。

然後我們提供一些簡單的掩碼示例:

          TeX  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 0 12 * * ? 每天12點觸發 0 15 10 ? * * 每天10點15分觸發 0 15 10 * * ? 每天10點15分觸發 0 15 10 * * ? * 每天10點15分觸發 0 15 10 * * ? 2005 2005年每天10點15分觸發 0 * 14 * * ? 每天下午的 2點到2點59分每分觸發 0 0/5 14 * * ? 每天下午的 2點到2點59分(整點開始,每隔5分觸發) 0 0/5 14,18 * * ? 每天下午的 2點到2點59分、18點到18點59分(整點開始,每隔5分觸發) 0 0-5 14 * * ? 每天下午的 2點到2點05分每分觸發 0 10,44 14 ? 3 WED 3月分每週三下午的 2點10分和2點44分觸發 0 15 10 ? * MON-FRI 從週一到週五每天上午的10點15分觸發 0 15 10 15 * ? 每月15號上午10點15分觸發 0 15 10 L * ? 每月最後一天的10點15分觸發 0 15 10 ? * 6L 每月最後一週的星期六的10點15分觸發 0 15 10 ? * 6L 2002-2005 從2002年到2005年每月最後一週的星期六的10點15分觸發 0 15 10 ? * 6#3 每月的第三週的星期六開始觸發 0 0 12 1/5 * ? 每月的第一個中午開始每隔5天觸發一次 0 11 11 11 11 ? 每年的11月11號 11點11分觸發(光棍節) 0 0 12,22 ? * W 每個工作日的 12:00:00 22:00:00 觸發 0 0 12,23 LW * * 每月最後一個工作日的 12:00:00 23:00:00 觸發 0 0 12,23 L-2W * * 每月最後一天再倒數兩天後最近的一個工作日觸發

如果有寫不明白的表示式,可以進群裡諮詢。

 

http://blog.qdac.cc/?p=2794