cron代码库
cron文档V3
cron文档
话不多说, 先上一个最简单, 开箱即用的例子
相关依赖 go get github.com/robfig/cron/[email protected]
示例代码
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
c.AddFunc("@every 3s", func() { fmt.Printf("Every 3 seconds, %s\n", time.Now().Format("15:04:05")) })
go c.Start()
c.AddFunc("@every 2s", func() { fmt.Printf("Every 2 seconds, %s\n", time.Now().Format("15:04:05")) })
defer c.Stop()
select {}
}
运行代码
go run main.go
运行结果
Every 2 seconds, 01:17:37
Every 3 seconds, 01:17:38
Every 2 seconds, 01:17:39
Every 2 seconds, 01:17:41
Every 3 seconds, 01:17:41
Every 2 seconds, 01:17:43
话不多说, 先上一个最简单, 开箱即用的例子
go get github.com/robfig/cron/[email protected]
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
// 每5秒执行一次
c.AddFunc("@every 5s", func() { fmt.Printf("Every five seconds, %s\n", time.Now().Format("15:04:05")) })
c.Start()
// 每10秒执行一次
c.AddFunc("@every 10s", func() { fmt.Printf("Every ten seconds, %s\n", time.Now().Format("15:04:05")) })
r := gin.Default()
r.Run()
}
go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
Every five seconds, 01:17:20
Every five seconds, 01:17:25
Every ten seconds, 01:17:25
Every five seconds, 01:17:30
Every ten seconds, 01:17:35
Every five seconds, 01:17:35
Every five seconds, 01:17:40
字段名 | 是否必填 | 允许的值 | 允许的特殊符号 |
---|---|---|---|
秒 Seconds(v3默认不支持 ) |
是 | 0-59 | * / , - |
分Minutes | 是 | 0-59 | * / , - |
时 Hours | 是 | 0-23 | * / , - |
日 Day of month | 是 | 1-31 | * / , - ? |
月 Month | 是 | 1-12 or JAN-DEC | * / , - |
周几 Day of week | 是 | 0-6 or SUN-SAT | * / , - ? |
asterisk ( * )
“每
”, 如:每分钟, 每小时
The asterisk indicates that the cron expression will match for all values of the field; e.g., using an asterisk in the 5th field (month) would indicate every month.
Slash ( / )
“每隔
”, */5
可以根据所在位置, 可表示每隔5分钟, 每隔5小时等
结合"-
", 3-59/15
(放着分钟位置的时候)表示第3分钟和此后每隔15分钟都执行, 知道59分钟为止
Slashes are used to describe increments of ranges. For example 3-59/15 in the 1st field (minutes) would indicate the 3rd minute of the hour and every 15 minutes thereafter. The form “*/…” is equivalent to the form “first-last/…”, that is, an increment over the largest possible range of the field. The form “N/…” is accepted as meaning “N-MAX/…”, that is, starting at N, use the increment until the end of that specific range. It does not wrap around.
Comma ( , )
分隔符
, 多个值的时候, 用来当分隔符
Commas are used to separate items of a list. For example, using “MON,WED,FRI” in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
Hyphen ( - )
范围
, 1-17, 可以表示, 凌晨1点到下午5点的每个小时
Hyphens are used to define ranges. For example, 9-17 would indicate every hour between 9am and 5pm inclusive.
Question mark ( ? )
同*
Question mark may be used instead of ‘*’ for leaving either day-of-month or day-of-week blank.
Entry | Description | Equivalent To |
---|---|---|
@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 * |
@monthly | Run once a month, midnight, first of month | 0 0 0 1 * * |
@weekly | Run once a week, midnight between Sat/Sun | 0 0 0 * * 0 |
@daily (or @midnight) | Run once a day, midnight | 0 0 0 * * * |
@hourly | Run once an hour, beginning of hour | 0 0 * * * * |
并非啥特殊需求, 纯粹是写demo的时候, 想写个每秒/每隔几秒执行一次的任务, 能明显看到定时任务是否添加成功和成功执行
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
c.AddFunc("* * * * * *", func() { fmt.Println("Every seconds") })
c.AddFunc("@every 5s", func() { fmt.Printf("Every five seconds, %s\n", time.Now().Format("15:04:05")) })
c.Start()
c.AddFunc("@every 10s", func() { fmt.Printf("Every ten seconds, %s\n", time.Now().Format("15:04:05")) })
r := gin.Default()
r.Run()
}
结果:
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
Every five seconds, 01:17:00
Every ten seconds, 01:17:05
Every five seconds, 01:17:05
Every five seconds, 01:17:10
Every five seconds, 01:17:15
Every ten seconds, 01:17:15
问题来了! 我每秒执行一次的定时任务被谁吞了呢?
由于我用的是 cron/v3
, 去看了看文档, 发现有这么一段说明, 大概意思就是, cron v3默认不支持秒级别的定时任务
Since adding Seconds is the most common modification to the standard cron spec, cron provides a builtin function to do that, which is equivalent to the custom parser you saw earlier, except that its seconds field is REQUIRED:
cron.New(cron.WithSeconds())
cron.New(cron.WithSeconds())
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
func main() {
// c := cron.New()
c := cron.New(cron.WithSeconds())
c.AddFunc("* * * * * *", func() { fmt.Println("Every seconds") })
c.AddFunc("@every 5s", func() { fmt.Printf("Every five seconds, %s\n", time.Now().Format("15:04:05")) })
c.Start()
c.AddFunc("@every 10s", func() { fmt.Printf("Every ten seconds, %s\n", time.Now().Format("15:04:05")) })
r := gin.Default()
r.Run()
}
这里推荐方案1
看了看, 现在使用的是cron.New()
cron.New()
源码如下:
func New(opts ...Option) *Cron {
c := &Cron{
entries: nil,
chain: NewChain(),
add: make(chan *Entry),
stop: make(chan struct{}),
snapshot: make(chan chan []Entry),
remove: make(chan EntryID),
running: false,
runningMu: sync.Mutex{},
logger: DefaultLogger,
location: time.Local,
parser: standardParser,
}
for _, opt := range opts {
opt(c)
}
return c
}
可以看到其中的parser
用的是standardParser
, standardParser
定义如下, 可以看出, 第一个参数不是秒
, 是分
var standardParser = NewParser(
Minute | Hour | Dom | Month | Dow | Descriptor,
)
再看了看, cron.WithSeconds()
的源码, 可以明显看出, 是修改了cron的parser
// WithSeconds overrides the parser used for interpreting job schedules to
// include a seconds field as the first one.
func WithSeconds() Option {
return WithParser(NewParser(
Second | Minute | Hour | Dom | Month | Dow | Descriptor,
))
}
// WithParser overrides the parser used for interpreting job schedules.
func WithParser(p Parser) Option {
return func(c *Cron) {
c.parser = p
}
}