定時任務 cron
阿新 • • 發佈:2022-05-31
cron表示式是我用過迄今為止最好用的定時器表達方式,比較的靈活,可以支援多種多樣的靈活的定時器。
先看最簡單的用法:
package main
import (
"fmt"
"github.com/robfig/cron"
)
func main() {
c := cron.New()
c.AddFunc("*/5 * * * * *", func() {
fmt.Println("每5秒執行一次")
})
c.Start()
select {}
}
如果業務比較複雜的話我們還可以進行更深一層次的封裝。
package main
import (
"fmt"
"github.com/robfig/cron"
)
func RunTimer(value string) {
fmt.Println(value)
fmt.Println("每5秒執行一次")
}
func main() {
c := cron.New()
c.AddFunc("*/5 * * * * *", func() {
RunTimer("傳入引數")
})
c.Start()
select {}
}
我們可以新增多條任務
package main
import (
"fmt"
"github.com/robfig/cron"
)
func RunTimer(value string) {
fmt. Println(value)
fmt.Println("每5秒執行一次")
}
func main() {
c := cron.New()
c.AddFunc("*/5 * * * * *", func() {
RunTimer("傳入引數")
})
c.AddFunc("*/5 * * * * *", func() {
RunTimer("第二條任務傳入引數")
})
c.Start()
select {}
}
還可以使用stop函式來停止我們的定時器
package main
import (
"fmt"
"github.com/robfig/cron"
)
func RunTimer(value string) {
fmt.Println(value)
fmt.Println("每5秒執行一次")
}
func main() {
c := cron.New()
c.AddFunc("*/5 * * * * *", func() {
RunTimer("傳入引數")
})
c.AddFunc("*/5 * * * * *", func() {
RunTimer("第二條任務傳入引數")
})
c.Start()
defer c.Stop()
}
除此之外還有一種job的方式,不過我認為這種方式用起來不是很直觀,不推薦使用
package main
import (
"fmt"
"github.com/robfig/cron"
)
type TestJob struct {
}
func (TestJob) Run() {
fmt.Println("每5秒執行一次")
}
func main() {
c := cron.New()
c.AddJob("*/5 * * * * *",TestJob{})
c.Start()
defer c.Stop()
}
除了cron表示式它還有一種自己特定的寫法
package main
import (
"fmt"
"github.com/robfig/cron"
)
func main() {
c := cron.New()
c.AddFunc("@hourly", func() {
fmt.Println("每個小時執行一次")
})
c.Start()
defer c.Stop()
}
package main
import (
"fmt"
"github.com/robfig/cron"
)
func main() {
c := cron.New()
c.AddFunc("@every 1h30m", func() {
fmt.Println("每個小時的第三十分鐘執行")
})
c.Start()
defer c.Stop()
}
不過還是有一些需要注意的點,這個庫的cron表示式和網上一些常規的cron表示式有點不同
可以看到網上一些線上生成的表示式是有7位的
我嘗試把它放進去
package main
import (
"fmt"
"github.com/robfig/cron"
)
func main() {
c := cron.New()
err:=c.AddFunc("0/1 * * * * ? *", func() {
fmt.Println("每一秒執行一次")
})
if err!=nil{
fmt.Println(err.Error())
}
c.Start()
select {
}
}
執行結果報錯了:
查看了官方文件發現他缺少了年份這一位 所以這裡不能使用常規的線上生成器生成的cron表示式去操作
還有一點就是它不支援刪除正在掛起的定時器任務
於是我做了一個改裝
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/robfig/cron"
uuid "github.com/satori/go.uuid"
)
var CronArray=make(map[string]cron.Cron)
func Get16MD5Encode(data string) string {
return GetMD5Encode(data)[8:24]
}
//獲取uuid
func GetUuid() string {
u := uuid.NewV4()
return Get16MD5Encode(u.String())
}
//返回一個32位md5加密後的字串
func GetMD5Encode(data string) string {
h := md5.New()
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
c := cron.New()
err:=c.AddFunc("0/1 * * * * ? *", func() {
fmt.Println("每一秒執行一次")
})
if err!=nil{
fmt.Println(err.Error())
}
c.Start()
cronId:=GetUuid()
CronArray[cronId]=*c
select {
}
}
如此一來我就可以通過map的key值傳入來執行stop函式來停止掉指定的cron定時器任務
但是這麼寫其實還是有風險的,當我們的程式非同步競爭map時可能出現map為空的錯誤
所以我們在改造一下
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/robfig/cron"
uuid "github.com/satori/go.uuid"
"sync"
)
var CronArray sync.Map
func Get16MD5Encode(data string) string {
return GetMD5Encode(data)[8:24]
}
//獲取uuid
func GetUuid() string {
u := uuid.NewV4()
return Get16MD5Encode(u.String())
}
//返回一個32位md5加密後的字串
func GetMD5Encode(data string) string {
h := md5.New()
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
c := cron.New()
err:=c.AddFunc("0/1 * * * * ? *", func() {
fmt.Println("每一秒執行一次")
})
if err!=nil{
fmt.Println(err.Error())
}
c.Start()
cronId:=GetUuid()
//新增cron定時器
CronArray.Store(cronId,*c)
//獲取指定cron定時器關閉
getCron,ok:=CronArray.Load(cronId)
if ok{
cronNew:=getCron.(cron.Cron)
cronNew.Stop()
}
select {
}
}
但是這就意味著我們每個cron只能新增一個addfunc或者addjob
後面有時間會嘗試一下把原始碼拿來二次改裝