為開源項目 go-gin-api 增加后臺任務(wù)模塊
文章目錄:
任務(wù)管理界面 (WEB)
任務(wù)調(diào)度器
任務(wù)執(zhí)行器
小結(jié)
推薦閱讀
任務(wù)管理界面 (WEB)

支持在 WEB 界面 中對任務(wù)進(jìn)行管理,例如:新增任務(wù)、編輯任務(wù)、啟用/禁用任務(wù)、手動執(zhí)行任務(wù) 等。
任務(wù)的屬性包括:
任務(wù)名稱 執(zhí)行方式 SHELLHTTP表達(dá)式(*/5 * * * *) 命令 超時時間(秒) 重試次數(shù) 重試間隔(秒) 執(zhí)行結(jié)束是否通知 不通知 失敗通知 結(jié)束通知 結(jié)果關(guān)鍵字匹配通知 狀態(tài) 備注
當(dāng)執(zhí)行方式為 HTTP 時,支持選擇請求方式 GET 或 POST;
當(dāng)設(shè)置執(zhí)行結(jié)束通知時,支持選擇通知方式 郵件 或 Webhook;
當(dāng)設(shè)置郵件通知時,支持輸入郵箱地址多個用,分割;
當(dāng)設(shè)置結(jié)果關(guān)鍵字匹配通知時,支持輸入關(guān)鍵字多個用,分割;
任務(wù)增加完成后,會把任務(wù)數(shù)據(jù)持久化到 MySQL 中。
任務(wù)調(diào)度器
參考了兩個開源組件:
robfig/cron[1] jakecoffman/cron[2]
最終選擇使用 jakecoffman/cron ,后者是在前者的基礎(chǔ)上做了一定的補(bǔ)充,例如 AddFunc() 增加了 name 參數(shù),同時還增加了 RemoveJob(name string) 支持刪除特定的任務(wù)。
// AddFunc adds a func to the Cron to be run on the given schedule.
func (c *Cron) AddFunc(spec string, cmd func(), name string) {
c.AddJob(spec, FuncJob(cmd), name)
}
...
// RemoveJob removes a Job from the Cron based on name.
func (c *Cron) RemoveJob(name string) {
if !c.running {
i := c.entries.pos(name)
if i == -1 {
return
}
c.entries = c.entries[:i+copy(c.entries[i:], c.entries[i+1:])]
return
}
c.remove <- name
}
對其簡單封裝下就可以使用了,下面是封裝的方法,方法的具體實現(xiàn)與使用從 go-gin-api[3] 中獲取。
type Server interface {
i()
// Start 啟動 cron 服務(wù)
Start()
// Stop 停止 cron 服務(wù)
Stop()
// AddTask 增加定時任務(wù)
AddTask(task *cron_task_repo.CronTask)
// RemoveTask 刪除定時任務(wù)
RemoveTask(taskId int)
// AddJob 增加定時任務(wù)執(zhí)行的工作內(nèi)容
AddJob(task *cron_task_repo.CronTask) cron.FuncJob
}
當(dāng)調(diào)用 Start() 啟動服務(wù)時,會把 MySQL 中的任務(wù)列表加載到調(diào)度器中。
通過以上方法,當(dāng)從 WEB 界面 操作 新增、編輯、啟用/禁用、手動執(zhí)行任務(wù)時,可以動態(tài)的對調(diào)度器中的任務(wù)進(jìn)行管理。
任務(wù)執(zhí)行器
任務(wù)執(zhí)行器指的是任務(wù)真實執(zhí)行所在的機(jī)器。
我的思路是使用 Kafka 的發(fā)布與訂閱功能,當(dāng)調(diào)度器發(fā)現(xiàn)需要執(zhí)行的任務(wù)時,將任務(wù)信息寫到 Kafka 的 Topic 中,任務(wù)執(zhí)行器訂閱相關(guān)的 Topic 獲取任務(wù)信息然后執(zhí)行任務(wù)。
如果任務(wù)的執(zhí)行方式為 HTTP,那么任務(wù)執(zhí)行器可以為一組集群,專門處理調(diào)用 HTTP 任務(wù),這里可以為一個消費(fèi)組(Consumer Group),也可適具體場景而定。
如果任務(wù)的執(zhí)行方式為 SHELL,那么任務(wù)執(zhí)行器必須在腳本所在的宿主機(jī)上,這里可以為一個具體任務(wù)的消費(fèi)者。
如果任務(wù)量過多,可以考慮根據(jù)業(yè)務(wù)場景多設(shè)置幾個 Topic。
在項目中為了便于演示,不寫入到 Kafka 中,僅記錄了日志。
func (s *server) AddJob(task *cron_task_repo.CronTask) cron.FuncJob {
return func() {
s.taskCount.Add()
defer s.taskCount.Done()
msg := fmt.Sprintf("開始執(zhí)行任務(wù):(%d)%s [%s]", task.Id, task.Name, task.Spec)
s.logger.Info(msg)
}
}
日志目錄:/logs/go-gin-api-cron.log。
小結(jié)
本文純屬拋磚引玉,有問題,歡迎批評指正。
go-gin-api 項目安裝簡單,開箱即用,創(chuàng)建一個后臺任務(wù)試試吧。
推薦閱讀
參考資料
robfig/cron: https://github.com/robfig/cron
[2]jakecoffman/cron: https://github.com/jakecoffman/cron
[3]go-gin-api: https://github.com/xinliangnote/go-gin-api
推薦閱讀
