mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 11:18:02 +08:00
improve package gcron
This commit is contained in:
parent
c4b28b0bc4
commit
2f0e5a45c5
@ -19,7 +19,6 @@ const (
|
||||
STATUS_RUNNING = gtimer.STATUS_RUNNING
|
||||
STATUS_STOPPED = gtimer.STATUS_STOPPED
|
||||
STATUS_CLOSED = gtimer.STATUS_CLOSED
|
||||
|
||||
gDEFAULT_TIMES = math.MaxInt32
|
||||
)
|
||||
|
||||
|
@ -9,6 +9,7 @@ package gcron
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -16,25 +17,26 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 运行时间管理对象
|
||||
// cronSchedule is the schedule for cron job.
|
||||
type cronSchedule struct {
|
||||
create int64 // 创建时间戳(秒)
|
||||
every int64 // 运行时间间隔(秒)
|
||||
pattern string // 原始注册字符串
|
||||
second map[int]struct{}
|
||||
minute map[int]struct{}
|
||||
hour map[int]struct{}
|
||||
day map[int]struct{}
|
||||
week map[int]struct{}
|
||||
month map[int]struct{}
|
||||
create int64 // Created timestamp.
|
||||
every int64 // Running interval in seconds.
|
||||
pattern string // The raw cron pattern string.
|
||||
second map[int]struct{} // Job can run in these second numbers.
|
||||
minute map[int]struct{} // Job can run in these minute numbers.
|
||||
hour map[int]struct{} // Job can run in these hour numbers.
|
||||
day map[int]struct{} // Job can run in these day numbers.
|
||||
week map[int]struct{} // Job can run in these week numbers.
|
||||
month map[int]struct{} // Job can run in these moth numbers.
|
||||
}
|
||||
|
||||
const (
|
||||
gREGEX_FOR_CRON = `^([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)$`
|
||||
// regular expression for cron pattern, which contains 6 parts of time units.
|
||||
gREGEX_FOR_CRON = `^([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,A-Za-z]+)\s+([\-/\d\*\?,A-Za-z]+)$`
|
||||
)
|
||||
|
||||
var (
|
||||
// 预定义的定时格式
|
||||
// Predefined pattern map.
|
||||
predefinedPatternMap = map[string]string{
|
||||
"@yearly": "0 0 0 1 1 *",
|
||||
"@annually": "0 0 0 1 1 *",
|
||||
@ -44,7 +46,7 @@ var (
|
||||
"@midnight": "0 0 0 * * *",
|
||||
"@hourly": "0 0 * * * *",
|
||||
}
|
||||
// 月份与数字对应表
|
||||
// Short month name to its number.
|
||||
monthMap = map[string]int{
|
||||
"jan": 1,
|
||||
"feb": 2,
|
||||
@ -59,7 +61,7 @@ var (
|
||||
"nov": 11,
|
||||
"dec": 12,
|
||||
}
|
||||
// 星期与数字对应表
|
||||
// Short week name to its number.
|
||||
weekMap = map[string]int{
|
||||
"sun": 0,
|
||||
"mon": 1,
|
||||
@ -71,15 +73,15 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// 解析定时格式为cronSchedule对象
|
||||
// newSchedule creates and returns a schedule object for given cron pattern.
|
||||
func newSchedule(pattern string) (*cronSchedule, error) {
|
||||
// 处理预定义的定时格式
|
||||
// Check if the predefined patterns.
|
||||
if match, _ := gregex.MatchString(`(@\w+)\s*(\w*)\s*`, pattern); len(match) > 0 {
|
||||
key := strings.ToLower(match[1])
|
||||
if v, ok := predefinedPatternMap[key]; ok {
|
||||
pattern = v
|
||||
} else if strings.Compare(key, "@every") == 0 {
|
||||
if d, err := time.ParseDuration(match[2]); err != nil {
|
||||
if d, err := gtime.ParseDuration(match[2]); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &cronSchedule{
|
||||
@ -92,44 +94,45 @@ func newSchedule(pattern string) (*cronSchedule, error) {
|
||||
return nil, errors.New(fmt.Sprintf(`invalid pattern: "%s"`, pattern))
|
||||
}
|
||||
}
|
||||
// 处理通用的定时格式定义
|
||||
// Handle the common cron pattern, like:
|
||||
// 0 0 0 1 1 2
|
||||
if match, _ := gregex.MatchString(gREGEX_FOR_CRON, pattern); len(match) == 7 {
|
||||
schedule := &cronSchedule{
|
||||
create: time.Now().Unix(),
|
||||
every: 0,
|
||||
pattern: pattern,
|
||||
}
|
||||
// 秒
|
||||
// Second.
|
||||
if m, err := parseItem(match[1], 0, 59, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.second = m
|
||||
}
|
||||
// 分
|
||||
// Minute.
|
||||
if m, err := parseItem(match[2], 0, 59, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.minute = m
|
||||
}
|
||||
// 时
|
||||
// Hour.
|
||||
if m, err := parseItem(match[3], 0, 23, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.hour = m
|
||||
}
|
||||
// 天
|
||||
// Day.
|
||||
if m, err := parseItem(match[4], 1, 31, true); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.day = m
|
||||
}
|
||||
// 月
|
||||
// Month.
|
||||
if m, err := parseItem(match[5], 1, 12, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.month = m
|
||||
}
|
||||
// 周
|
||||
// Week.
|
||||
if m, err := parseItem(match[6], 0, 6, true); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@ -141,7 +144,7 @@ func newSchedule(pattern string) (*cronSchedule, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 解析定时格式中的每一项定时配置
|
||||
// parseItem parses every item in the pattern and returns the result as map.
|
||||
func parseItem(item string, min int, max int, allowQuestionMark bool) (map[int]struct{}, error) {
|
||||
m := make(map[int]struct{}, max-min+1)
|
||||
if item == "*" || (allowQuestionMark && item == "?") {
|
||||
@ -159,19 +162,23 @@ func parseItem(item string, min int, max int, allowQuestionMark bool) (map[int]s
|
||||
interval = i
|
||||
}
|
||||
}
|
||||
rangeMin := min
|
||||
rangeMax := max
|
||||
rangeArray := strings.Split(intervalArray[0], "-")
|
||||
valueType := byte(0)
|
||||
var (
|
||||
rangeMin = min
|
||||
rangeMax = max
|
||||
fieldType = byte(0)
|
||||
rangeArray = strings.Split(intervalArray[0], "-") // Like: 1-30, JAN-DEC
|
||||
)
|
||||
switch max {
|
||||
case 6:
|
||||
valueType = 'w'
|
||||
case 11:
|
||||
valueType = 'm'
|
||||
// It's checking week field.
|
||||
fieldType = 'w'
|
||||
case 12:
|
||||
// It's checking month field.
|
||||
fieldType = 'm'
|
||||
}
|
||||
// 例如: */5
|
||||
// Eg: */5
|
||||
if rangeArray[0] != "*" {
|
||||
if i, err := parseItemValue(rangeArray[0], valueType); err != nil {
|
||||
if i, err := parseItemValue(rangeArray[0], fieldType); err != nil {
|
||||
return nil, errors.New(fmt.Sprintf(`invalid pattern item: "%s"`, item))
|
||||
} else {
|
||||
rangeMin = i
|
||||
@ -179,7 +186,7 @@ func parseItem(item string, min int, max int, allowQuestionMark bool) (map[int]s
|
||||
}
|
||||
}
|
||||
if len(rangeArray) == 2 {
|
||||
if i, err := parseItemValue(rangeArray[1], valueType); err != nil {
|
||||
if i, err := parseItemValue(rangeArray[1], fieldType); err != nil {
|
||||
return nil, errors.New(fmt.Sprintf(`invalid pattern item: "%s"`, item))
|
||||
} else {
|
||||
rangeMax = i
|
||||
@ -193,38 +200,41 @@ func parseItem(item string, min int, max int, allowQuestionMark bool) (map[int]s
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// 将配置项值转换为数字
|
||||
func parseItemValue(value string, valueType byte) (int, error) {
|
||||
// parseItemValue parses the field value to a number according to its field type.
|
||||
func parseItemValue(value string, fieldType byte) (int, error) {
|
||||
if gregex.IsMatchString(`^\d+$`, value) {
|
||||
// 纯数字
|
||||
// Pure number.
|
||||
if i, err := strconv.Atoi(value); err == nil {
|
||||
return i, nil
|
||||
}
|
||||
} else {
|
||||
// 英文字母
|
||||
switch valueType {
|
||||
// Check if contains letter,
|
||||
// it converts the value to number according to predefined map.
|
||||
switch fieldType {
|
||||
case 'm':
|
||||
if i, ok := monthMap[strings.ToLower(value)]; ok {
|
||||
return int(i), nil
|
||||
return i, nil
|
||||
}
|
||||
case 'w':
|
||||
if i, ok := weekMap[strings.ToLower(value)]; ok {
|
||||
return int(i), nil
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, errors.New(fmt.Sprintf(`invalid pattern value: "%s"`, value))
|
||||
}
|
||||
|
||||
// 判断给定的时间是否满足schedule
|
||||
// meet checks if the given time <t> meets the runnable point for the job.
|
||||
func (s *cronSchedule) meet(t time.Time) bool {
|
||||
if s.every != 0 {
|
||||
// It checks using interval.
|
||||
diff := t.Unix() - s.create
|
||||
if diff > 0 {
|
||||
return diff%s.every == 0
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
// It checks using normal cron pattern.
|
||||
if _, ok := s.second[t.Second()]; !ok {
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user