feat: timer.Ticker 新增 Cron 函数,支持通过 Cron 表达式下发定时任务

This commit is contained in:
kercylan98 2023-11-27 14:30:39 +08:00
parent 844fb3059e
commit 4117607c8f
5 changed files with 59 additions and 7 deletions

1
go.mod
View File

@ -36,6 +36,7 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect

4
go.sum
View File

@ -76,6 +76,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@ -132,6 +134,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=

View File

@ -1,6 +1,7 @@
package timer
import (
"github.com/gorhill/cronexpr"
"reflect"
"sync"
"time"
@ -26,6 +27,8 @@ type Scheduler struct {
ticker *Ticker
lock sync.RWMutex
expr *cronexpr.Expression
}
// Name 获取调度器名称
@ -38,9 +41,13 @@ func (slf *Scheduler) Next(prev time.Time) time.Time {
slf.lock.RLock()
defer slf.lock.RUnlock()
if slf.kill || (slf.total > 0 && slf.trigger > slf.total) {
if slf.kill || (slf.expr != nil && slf.total > 0 && slf.trigger > slf.total) {
return time.Time{}
}
if slf.expr != nil {
next := slf.expr.Next(prev)
return next
}
if slf.trigger == 0 {
slf.trigger++
return prev.Add(slf.after)

View File

@ -1,6 +1,7 @@
package timer
import (
"github.com/gorhill/cronexpr"
"reflect"
"sync"
"time"
@ -72,20 +73,33 @@ func (slf *Ticker) GetSchedulers() []string {
return names
}
// Cron 通过 cron 表达式设置一个调度器,当 cron 表达式错误时,将会引发 panic
func (slf *Ticker) Cron(name, expression string, handleFunc interface{}, args ...interface{}) {
expr := cronexpr.MustParse(expression)
slf.loop(name, 0, 0, expr, 0, handleFunc, args...)
}
// After 设置一个在特定时间后运行一次的调度器
func (slf *Ticker) After(name string, after time.Duration, handleFunc interface{}, args ...interface{}) {
slf.Loop(name, after, timingWheelTick, 1, handleFunc, args...)
slf.loop(name, after, timingWheelTick, nil, 1, handleFunc, args...)
}
// Loop 设置一个在特定时间后反复运行的调度器
func (slf *Ticker) Loop(name string, after, interval time.Duration, times int, handleFunc interface{}, args ...interface{}) {
slf.loop(name, after, interval, nil, times, handleFunc, args...)
}
// Loop 设置一个在特定时间后反复运行的调度器
func (slf *Ticker) loop(name string, after, interval time.Duration, expr *cronexpr.Expression, times int, handleFunc interface{}, args ...interface{}) {
slf.StopTimer(name)
if after < timingWheelTick {
after = timingWheelTick
}
if interval < timingWheelTick {
interval = timingWheelTick
if expr == nil {
if after < timingWheelTick {
after = timingWheelTick
}
if interval < timingWheelTick {
interval = timingWheelTick
}
}
var values = make([]reflect.Value, len(args))
@ -101,6 +115,7 @@ func (slf *Ticker) Loop(name string, after, interval time.Duration, times int, h
cbFunc: reflect.ValueOf(handleFunc),
cbArgs: values,
ticker: slf,
expr: expr,
}
slf.lock.Lock()

View File

@ -0,0 +1,25 @@
package timer_test
import (
"github.com/kercylan98/minotaur/utils/timer"
"github.com/kercylan98/minotaur/utils/times"
"testing"
"time"
)
func TestTicker_Cron(t *testing.T) {
ticker := timer.GetTicker(10)
ticker.After("1_sec", time.Second, func() {
t.Log(time.Now().Format(time.DateTime), "1_sec")
})
ticker.Loop("1_sec_loop_3", 0, time.Second, 3, func() {
t.Log(time.Now().Format(time.DateTime), "1_sec_loop_3")
})
ticker.Cron("5_sec_cron", "0/5 * * * * * ?", func() {
t.Log(time.Now().Format(time.DateTime), "5_sec_cron")
})
time.Sleep(times.Week)
}