diff --git a/go.mod b/go.mod index 3dadec3..36c7a6d 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 91205e9..db67b8c 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/utils/timer/scheduler.go b/utils/timer/scheduler.go index ffa6ee5..aac4f81 100644 --- a/utils/timer/scheduler.go +++ b/utils/timer/scheduler.go @@ -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) diff --git a/utils/timer/ticker.go b/utils/timer/ticker.go index b3a4b1b..de59f93 100644 --- a/utils/timer/ticker.go +++ b/utils/timer/ticker.go @@ -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() diff --git a/utils/timer/ticker_test.go b/utils/timer/ticker_test.go new file mode 100644 index 0000000..b568f13 --- /dev/null +++ b/utils/timer/ticker_test.go @@ -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) +}