Golang 的多任務調度系統:從 BaseJob 到 ProductJob 的 "泛型" 與 "繼承" 實現
突破 Go 語言限制! 揭祕如何用組合 + 接口實現類繼承效果,打造高擴展任務調度系統。以 BaseJob 泛型基類和 ProductJob 實戰爲例,深度解析:
-
配置泛型化設計
-
方法重寫技巧
-
運行時多態實現 讓您的 Go 應用輕鬆處理百萬級定時任務!💪🚀
- 基礎架構:BaseJob 的 "泛型" 實現
在 lib/basejob.go 中,我們定義了一個基礎任務結構體,它使用類型參數實現了類似泛型的功能:
type BaseJob[T model.JobConfig] struct {
JobConfig T
JobName string
Description string
RetryCount int
EasyFunc interface{}
}
這裏的關鍵點是:
- 類型參數 T:約束爲 model.JobConfig,確保所有任務配置都符合特定接口
- 通用字段:JobName, Description, RetryCount 等字段對所有任務通用
- 方法實現:提供了錯誤處理、配置管理、狀態保存等通用方法
func (job *BaseJob[T]) DoError(err error, description string) {
job.RetryCount++
log.Println(description, err)
// 更新任務狀態
}
func (job *BaseJob[T]) GetSyncConfig() error {
// 獲取任務配置的通用實現
}
- "繼承" 模式:ProductJob 的實現
在 jobs/productjob/easyjob.go 中,我們通過組合實現了類似繼承的模式:
type EasyJob[T model.ByIdConfig] struct {
easylib.BaseJob[model.ByIdConfig]
}
這裏的關鍵設計:
- 嵌入 BaseJob:ProductJob 通過嵌入 BaseJob 獲得所有基礎功能
- 方法重寫:ProductJob 重寫了關鍵方法來實現具體業務邏輯
方法重寫示例
數據獲取方法重寫:
func (job *EasyJob[T]) GetDataPageList() ([]interface{}, []interface{}, interface{}, error) {
jobConfig := job.JobConfig
maxPid := easylib.GetMaxPid()
if jobConfig.Lastid >= maxPid {
return nil, nil, maxPid, nil
}
// 調用具體業務查詢
products, delProducts, lastId, err := QueryProduct(jobConfig.Lastid, jobConfig.Limit)
data := easylib.MapperFromProducts(products)
deleteData := easylib.MapperFromProducts(delProducts)
return data, deleteData, lastId, nil
}
ES 更新方法重寫:
func (job *EasyJob[T]) UpdateEs(data []interface{}) error {
ps := easylib.MapperToProducts(data)
err := products.BulkInsert(ps)
return err
}
- 多態實現:接口與運行時綁定
在 BaseJob 的 Run 方法中,我們通過類型斷言實現了運行時多態:
func (job *BaseJob[T]) Run() {
// ...
data, delData, last, err := job.EasyFunc.(EasyFunc).GetDataPageList()
// ...
err := job.EasyFunc.(EasyFunc).UpdateEs(data)
// ...
}
這裏的關鍵:
- EasyFunc 接口:定義了任務需要實現的方法
- 運行時綁定:通過類型斷言
job.EasyFunc.(EasyFunc)調用具體實現
- 任務管理器設計
任務管理器 (lib/jobmanager.go) 統一管理所有任務:
type EasyJobParam struct {
JobName string
Status int
Description string
RetryCount int
Interval time.Duration
}
var EasyJobManager = struct {
Jobs map[string]*EasyJobParam
Lock sync.RWMutex
}{
Jobs: make(map[string]*EasyJobParam),
}
總結
通過這種設計,我們實現了:
- 配置泛型化:通過類型參數支持不同任務的配置
- 代碼複用:BaseJob 提供通用實現,減少重複代碼
- 靈活擴展:新任務只需嵌入 BaseJob 並重寫關鍵方法
- 統一管理:任務管理器集中控制所有任務狀態
雖然 Golang 沒有傳統面向對象的繼承機制,但通過組合 + 接口 + 方法重寫,我們實現了同樣強大的抽象能力。這種模式在需要高擴展性的系統中特別有用,如我們的任務調度系統。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/L-u_Ad9NZFO131NmV54jQQ