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
后面有时间会尝试一下把源码拿来二次改装