架構
本頁說明 go-scheduler 如何解析排程、分派任務、追蹤依賴,以及在停止時完成收尾。
系統總覽
graph TB
App[應用程式] --> Cron[cron 排程器]
Cron --> Parser[Cron 解析器]
Cron --> Heap[任務最小堆]
Cron --> Depend[依賴子系統]
Depend --> Workers[依賴 Worker]
Heap --> Runner[任務執行器]
Workers --> Runner
Runner --> State[任務狀態更新]
排程器生命週期
core.New 建立排程器,初始化時區、logger、channel、最小堆、解析器與依賴管理器。當 Config.Location 為 nil 時,排程器使用 time.Local。logger 優先寫入 syslog;syslog 無法使用時,回退至 stderr。
排程器執行期間重複呼叫 Start 不會重複啟動。Start 會啟動依賴 Worker,為已註冊任務計算第一次觸發時間,接著進入事件迴圈。事件迴圈以 timer 等待最小堆中最近的任務;timer 觸發後,排程器取出到期任務、分派執行,並在仍有下一次觸發時間時重新放回堆中。
Add、Remove 與 RemoveAll 可以在排程器執行期間呼叫,此時透過 channel 安全地更新事件迴圈;在 Start 之前則直接更新最小堆。Stop 會停止事件迴圈與依賴 Worker,並回傳一個在所有進行中任務結束後才取消的 context。
排程流程
Add解析五欄位 Cron、描述符或@every間隔。- 任務取得單調遞增的
int64ID,並加入最小堆。 Start依設定的時區計算下一次觸發時間。- 事件迴圈取出最近到期的任務。
- 沒有依賴的任務直接執行;有依賴的任務加入依賴佇列。
- 任務結果將狀態更新為完成或失敗。
- 週期任務取得新的觸發時間,再次加入最小堆。
依賴子系統
具有依賴的任務會保存一組 Wait。依賴 Worker 透過管理器檢查每個前置任務:
| 前置任務狀態 | Wait.State |
後續任務行為 |
|---|---|---|
| 已完成 | 任一 | 繼續檢查其他前置任務。 |
| 失敗 | Stop |
依賴檢查失敗,後續任務不執行。 |
| 失敗 | Skip |
略過該失敗前置任務,繼續等待其他任務。 |
| 等待中或執行中 | 任一 | 持續等待完成或逾時。 |
| 不存在 | 任一 | 回傳找不到依賴任務的錯誤。 |
依賴子系統至少啟動兩個 Worker;當主機 CPU 數量大於兩個時,Worker 數量會擴充至 runtime.NumCPU()。依賴檢查使用 context 控制逾時;當等待時間為零時,Worker 佇列使用一分鐘的預設值。
排程資料結構
排程器使用按照 task.next 排序的 taskHeap 最小堆,因此事件迴圈只需要等待堆頂項目。解析結果實作共用的 schedule 介面。Cron 排程會逐分鐘向前搜尋符合時間;@every 排程則以目前時間加上固定間隔計算下一次觸發時間。
Cron 欄位支援 *、單一數值、範圍、逗號分隔列表與 */n 步進格式。任務加入前,解析器會依照各欄位允許的範圍驗證輸入。
執行與失敗處理
每個任務都會記錄 pending、running、completed 或 failed 狀態。任務動作可以是 func() 或 func() error;啟用依賴的任務必須回傳 error,才能傳遞失敗結果。設定執行時限後,任務會在 deadline 下執行,逾時時呼叫 onDelay。回傳錯誤與捕捉到的 panic 都會被視為任務失敗。