1. 程式人生 > 其它 >定時任務 cron

定時任務 cron

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

後面有時間會嘗試一下把原始碼拿來二次改裝