TODO: 修复时间控制的bug
This commit is contained in:
parent
19a4034928
commit
0dce1192d2
86
base.go
Normal file
86
base.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package crontab
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"474420502.top/eson/structure/priority_list"
|
||||
randomdata "github.com/Pallinder/go-randomdata"
|
||||
)
|
||||
|
||||
type randLR struct {
|
||||
left, right int
|
||||
}
|
||||
|
||||
// NodeCount 用于priority_list
|
||||
type NodeCount struct {
|
||||
plist.Node
|
||||
randLR
|
||||
}
|
||||
|
||||
// Compare NodeCount比较函数
|
||||
func (rlr *NodeCount) Compare(v plist.INode) bool {
|
||||
return rlr.GetValue().(int) > v.GetValue().(int)
|
||||
}
|
||||
|
||||
func parseRandLR(lrvalue string) randLR {
|
||||
vlen := len(lrvalue)
|
||||
lastchar := lrvalue[vlen-1]
|
||||
|
||||
lr := strings.Split(lrvalue, "-")
|
||||
switch len(lr) {
|
||||
case 1:
|
||||
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)}
|
||||
return lr
|
||||
case 2:
|
||||
|
||||
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)}
|
||||
return lr
|
||||
default:
|
||||
panic("lr is error")
|
||||
}
|
||||
}
|
||||
|
||||
// intervalPriorityListISecond 获取优先链表比较的值
|
||||
func intervalPriorityListISecond(planlist *plist.PriorityList, count int) int {
|
||||
|
||||
if planlist.Size() > 0 {
|
||||
node := new(NodeCount)
|
||||
node.SetValue(count)
|
||||
|
||||
iwantNode := planlist.GetCompare(node)
|
||||
if iwantNode != nil {
|
||||
wantNode := iwantNode.(*NodeCount)
|
||||
lr := wantNode.randLR
|
||||
return randomdata.Number(lr.left, lr.right+1)
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func getInt(v string) int {
|
||||
vint, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return vint
|
||||
}
|
||||
|
||||
func parseTimeValue(v string, lastchar byte) int {
|
||||
|
||||
vlen := len(v)
|
||||
|
||||
switch lastchar {
|
||||
case 's':
|
||||
return getInt(v[:vlen-1])
|
||||
case 'm':
|
||||
return getInt(v[:vlen-1]) * 60
|
||||
case 'h':
|
||||
return getInt(v[:vlen-1]) * 3600
|
||||
case 'd':
|
||||
return getInt(v[:vlen-1]) * 3600 * 24
|
||||
default:
|
||||
return getInt(v)
|
||||
}
|
||||
}
|
135
crontab.go
135
crontab.go
|
@ -10,23 +10,15 @@ import (
|
|||
"time"
|
||||
|
||||
"474420502.top/eson/structure/circular_linked"
|
||||
"474420502.top/eson/structure/priority_list"
|
||||
"github.com/Pallinder/go-randomdata"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type randLR struct {
|
||||
left, right int
|
||||
}
|
||||
|
||||
type randLRC struct {
|
||||
randLR
|
||||
count int
|
||||
}
|
||||
|
||||
type hInterval struct {
|
||||
PlanFailCount []randLRC
|
||||
PlanTrueCount []randLRC
|
||||
PlanFailCount plist.PriorityList
|
||||
PlanTrueCount plist.PriorityList
|
||||
|
||||
PlanFail []randLR
|
||||
PlanTrue []randLR
|
||||
|
@ -107,7 +99,7 @@ func (cron *Crontab) GetStatus() (status bool) {
|
|||
return cron.lastStatus
|
||||
}
|
||||
|
||||
// TimeUp 是否时间快到
|
||||
// TimeUp 是否时间快到, 时间间隔调用完TimeUp后必须调用NextTime, 为了精准控制时间
|
||||
func (cron *Crontab) TimeUp() bool {
|
||||
|
||||
if cron.interval != nil {
|
||||
|
@ -243,19 +235,34 @@ func (cron *Crontab) intervalCalculateNextTime(now time.Time) {
|
|||
|
||||
if cron.lastStatus == false {
|
||||
|
||||
if len(iv.PlanFailCount) > 0 {
|
||||
|
||||
} else if len(iv.PlanFail) > 0 {
|
||||
idx := randomdata.Number(len(iv.PlanFail))
|
||||
lr := iv.PlanFail[idx]
|
||||
isecond = randomdata.Number(lr.left, lr.right+1)
|
||||
isecond = intervalPriorityListISecond(&iv.PlanFailCount, iv.FailCount)
|
||||
if isecond == -1 {
|
||||
if len(iv.PlanFail) > 0 {
|
||||
idx := randomdata.Number(len(iv.PlanFail))
|
||||
lr := iv.PlanFail[idx]
|
||||
isecond = randomdata.Number(lr.left, lr.right+1)
|
||||
} else {
|
||||
isecond = 0
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("fail:", iv.FailCount, "count time wait:", isecond, "s")
|
||||
} else {
|
||||
idx := randomdata.Number(len(iv.PlanTrue))
|
||||
lr := iv.PlanTrue[idx]
|
||||
isecond = randomdata.Number(lr.left, lr.right+1)
|
||||
|
||||
isecond = intervalPriorityListISecond(&iv.PlanTrueCount, iv.TrueCount)
|
||||
if isecond == -1 {
|
||||
if len(iv.PlanTrue) > 0 {
|
||||
idx := randomdata.Number(len(iv.PlanTrue))
|
||||
lr := iv.PlanTrue[idx]
|
||||
isecond = randomdata.Number(lr.left, lr.right+1)
|
||||
|
||||
} else {
|
||||
isecond = 0
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Println("success:", iv.TrueCount, "count time wait:", isecond, "s")
|
||||
}
|
||||
}
|
||||
|
||||
iv.Count--
|
||||
|
@ -263,16 +270,19 @@ func (cron *Crontab) intervalCalculateNextTime(now time.Time) {
|
|||
iv.reset()
|
||||
cron.interval.MoveNext()
|
||||
}
|
||||
|
||||
cron.isCalculated = true
|
||||
cron.nextTime = now.Add(time.Duration(isecond) * time.Second)
|
||||
}
|
||||
|
||||
func (cron *Crontab) intervalTimeUp() bool {
|
||||
|
||||
now := time.Now()
|
||||
|
||||
if now.Unix() >= cron.nextTime.Unix() {
|
||||
cron.isCalculated = false
|
||||
return true
|
||||
if cron.isCalculated != false {
|
||||
now := time.Now()
|
||||
if now.Unix() >= cron.nextTime.Unix() {
|
||||
cron.isCalculated = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -355,7 +365,7 @@ func createTimePointer(min string, llimit, rlimit int, fixedLeftRight bool) []ti
|
|||
}
|
||||
}
|
||||
|
||||
// 全部符合 当左等于左 且 右等于右最大 并且 per == 1 TODO: 如果加入时间间隔 就需要 加多一个 附加值
|
||||
// 全部符合 当左等于左 且 右等于右最大 并且 per == 1
|
||||
if leftfixed == tp.leftlimit && rightfixed == tp.rightlimit && tp.per == 1 {
|
||||
tp.isAll = true
|
||||
}
|
||||
|
@ -402,19 +412,31 @@ func parseIntervalString(crontab string) []interface{} {
|
|||
case 'f', 'F':
|
||||
scharIndex := strings.Index(FN, "?")
|
||||
if scharIndex != -1 {
|
||||
|
||||
fc := FN[0:scharIndex]
|
||||
flr := FN[scharIndex+1:]
|
||||
interval.PlanFailCount = append(interval.PlanFailCount, parseRandLRC(fc, flr))
|
||||
|
||||
node := new(NodeCount)
|
||||
node.SetValue(getInt(fc[1:]))
|
||||
node.randLR = parseRandLR(flr)
|
||||
interval.PlanFailCount.Insert(node)
|
||||
|
||||
} else {
|
||||
fvalue := FN[1:]
|
||||
interval.PlanFail = append(interval.PlanFail, parseRandLR(fvalue))
|
||||
}
|
||||
|
||||
case 't', 'T':
|
||||
scharIndex := strings.Index(FN, "?")
|
||||
if scharIndex != -1 {
|
||||
tc := FN[0:scharIndex]
|
||||
tlr := FN[scharIndex+1:]
|
||||
interval.PlanTrueCount = append(interval.PlanTrueCount, parseRandLRC(tc, tlr))
|
||||
|
||||
node := new(NodeCount)
|
||||
node.SetValue(getInt(tc[1:]))
|
||||
node.randLR = parseRandLR(tlr)
|
||||
interval.PlanTrueCount.Insert(node)
|
||||
|
||||
} else {
|
||||
tvalue := FN[1:]
|
||||
interval.PlanTrue = append(interval.PlanTrue, parseRandLR(tvalue))
|
||||
|
@ -426,7 +448,12 @@ func parseIntervalString(crontab string) []interface{} {
|
|||
if scharIndex != -1 {
|
||||
tc := FN[0:scharIndex]
|
||||
tlr := FN[scharIndex+1:]
|
||||
interval.PlanTrueCount = append(interval.PlanTrueCount, parseRandLRC(tc, tlr))
|
||||
|
||||
node := new(NodeCount)
|
||||
node.SetValue(getInt(tc[1:]))
|
||||
node.randLR = parseRandLR(tlr)
|
||||
interval.PlanTrueCount.Insert(node)
|
||||
|
||||
} else {
|
||||
tvalue := FN[1:]
|
||||
interval.PlanTrue = append(interval.PlanTrue, parseRandLR(tvalue))
|
||||
|
@ -440,51 +467,3 @@ func parseIntervalString(crontab string) []interface{} {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
func parseRandLRC(fc, flr string) randLRC {
|
||||
return randLRC{count: getInt(fc[1:]), randLR: parseRandLR(flr)}
|
||||
}
|
||||
|
||||
func parseRandLR(lrvalue string) randLR {
|
||||
vlen := len(lrvalue)
|
||||
lastchar := lrvalue[vlen-1]
|
||||
|
||||
lr := strings.Split(lrvalue, "-")
|
||||
switch len(lr) {
|
||||
case 1:
|
||||
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)}
|
||||
return lr
|
||||
case 2:
|
||||
|
||||
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)}
|
||||
return lr
|
||||
default:
|
||||
panic("lr is error")
|
||||
}
|
||||
}
|
||||
|
||||
func getInt(v string) int {
|
||||
vint, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return vint
|
||||
}
|
||||
|
||||
func parseTimeValue(v string, lastchar byte) int {
|
||||
|
||||
vlen := len(v)
|
||||
|
||||
switch lastchar {
|
||||
case 's':
|
||||
return getInt(v[:vlen-1])
|
||||
case 'm':
|
||||
return getInt(v[:vlen-1]) * 60
|
||||
case 'h':
|
||||
return getInt(v[:vlen-1]) * 3600
|
||||
case 'd':
|
||||
return getInt(v[:vlen-1]) * 3600 * 24
|
||||
default:
|
||||
return getInt(v)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package crontab
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -37,12 +38,12 @@ func TestParseCrontab(t *testing.T) {
|
|||
func TestParseInterval(t *testing.T) {
|
||||
//crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围
|
||||
//crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f22?15-12"
|
||||
crontab := "2"
|
||||
crontab := "2s"
|
||||
cron := NewCrontab(crontab)
|
||||
now := time.Now()
|
||||
for i := 0; i <= 6; i++ {
|
||||
for i := 0; i <= 3; i++ {
|
||||
log.Println(cron.NextTime())
|
||||
if cron.TimeUp() {
|
||||
|
||||
sec := time.Since(now).Seconds()
|
||||
if i != 0 {
|
||||
if 2.0 <= sec && sec <= 2.1 {
|
||||
|
@ -65,6 +66,52 @@ func TestParseIntervalPlus(t *testing.T) {
|
|||
//crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围
|
||||
//crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f1" ^代表往后算 ^5 2月份就代表 28-4=24 f代表失败后1-2秒设置 由SetStatus控制 t 相反默认不写前缀为t
|
||||
|
||||
crontab := "f2|f2?3|f3?4|1"
|
||||
cron := NewCrontab(crontab)
|
||||
now := time.Now()
|
||||
t.Error("")
|
||||
for i := 0; i <= 5*15; i++ {
|
||||
cron.NextTime()
|
||||
if cron.TimeUp() {
|
||||
sec := time.Since(now).Seconds()
|
||||
cron.SetStatus(false)
|
||||
t.Error(i, sec)
|
||||
if i == 0 {
|
||||
if 1.0 <= sec && sec <= 1.1 {
|
||||
t.Log(sec)
|
||||
} else {
|
||||
t.Error(i, "interval time is ", sec)
|
||||
}
|
||||
}
|
||||
|
||||
if i == 1 {
|
||||
if 2.0 <= sec && sec <= 2.1 {
|
||||
t.Log(sec)
|
||||
} else {
|
||||
t.Error(i, "interval time is ", sec)
|
||||
}
|
||||
}
|
||||
|
||||
if i == 2 {
|
||||
if 3.0 <= sec && sec <= 3.1 {
|
||||
t.Log(sec)
|
||||
} else {
|
||||
t.Error(i, "interval time is ", sec)
|
||||
}
|
||||
}
|
||||
|
||||
if i == 3 {
|
||||
if 4.0 <= sec && sec <= 4.1 {
|
||||
t.Log(sec)
|
||||
} else {
|
||||
t.Error(i, "interval time is ", sec)
|
||||
}
|
||||
}
|
||||
|
||||
now = time.Now()
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
}
|
||||
}
|
||||
|
||||
func PrintMemUsage() {
|
||||
|
|
120
priority_list.go
120
priority_list.go
|
@ -1,120 +0,0 @@
|
|||
package crontab
|
||||
|
||||
import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
// INode 比较的必须继承的接口
|
||||
type INode interface {
|
||||
Compare(v INode) bool
|
||||
|
||||
// GetValue 获取值
|
||||
GetValue() interface{}
|
||||
// SetValue 设置值
|
||||
SetValue(v interface{})
|
||||
|
||||
GetPrev() INode
|
||||
SetPrev(INode)
|
||||
GetNext() INode
|
||||
SetNext(INode)
|
||||
}
|
||||
|
||||
// Node 优先链表的节点
|
||||
type Node struct {
|
||||
INode
|
||||
prev, next INode
|
||||
// isrelease bool
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// NewNode 创建一个PriorityList 节点
|
||||
func NewNode(v interface{}) *Node {
|
||||
n := new(Node)
|
||||
n.SetValue(v)
|
||||
return n
|
||||
}
|
||||
|
||||
// GetValue 获取值
|
||||
func (node *Node) GetValue() interface{} {
|
||||
return node.value
|
||||
}
|
||||
|
||||
// SetValue 设置值
|
||||
func (node *Node) SetValue(v interface{}) {
|
||||
node.value = v
|
||||
}
|
||||
|
||||
// GetPrev 获取left值
|
||||
func (node *Node) GetPrev() INode {
|
||||
return node.prev
|
||||
}
|
||||
|
||||
// SetPrev 设置left值
|
||||
func (node *Node) SetPrev(n INode) {
|
||||
node.prev = n
|
||||
}
|
||||
|
||||
// GetNext 设置right值
|
||||
func (node *Node) GetNext() INode {
|
||||
return node.next
|
||||
}
|
||||
|
||||
// SetNext 获取left值
|
||||
func (node *Node) SetNext(n INode) {
|
||||
node.next = n
|
||||
}
|
||||
|
||||
// PriorityList 优先列表
|
||||
type PriorityList struct {
|
||||
head INode
|
||||
}
|
||||
|
||||
func (pl *PriorityList) String() string {
|
||||
content := "["
|
||||
|
||||
cur := pl.head
|
||||
for cur != nil {
|
||||
content += spew.Sprint(cur.GetValue()) + "<->"
|
||||
cur = cur.GetNext()
|
||||
}
|
||||
|
||||
if content[len(content)-3:] == "<->" {
|
||||
content = content[:len(content)-3]
|
||||
}
|
||||
|
||||
content += "]"
|
||||
return content
|
||||
}
|
||||
|
||||
func (pl *PriorityList) InsertValue(node INode) {
|
||||
|
||||
if pl.head == nil {
|
||||
pl.head = node
|
||||
} else {
|
||||
cur := pl.head
|
||||
var prev INode
|
||||
for cur != nil {
|
||||
if !cur.Compare(node) {
|
||||
// 插入该值
|
||||
prev = cur.GetPrev()
|
||||
if prev == nil {
|
||||
node.SetNext(pl.head)
|
||||
pl.head = node
|
||||
} else {
|
||||
prev.SetNext(node)
|
||||
node.SetNext(cur)
|
||||
cur.SetPrev(node)
|
||||
node.SetPrev(prev)
|
||||
return
|
||||
}
|
||||
}
|
||||
cur = cur.GetNext()
|
||||
}
|
||||
prev.SetNext(node)
|
||||
}
|
||||
}
|
||||
|
||||
// New 创建 PriorityList
|
||||
func New() *PriorityList {
|
||||
return new(PriorityList)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package crontab
|
||||
|
||||
import "testing"
|
||||
|
||||
type FL struct {
|
||||
Node
|
||||
}
|
||||
|
||||
func (fl *FL) Compare(v INode) bool {
|
||||
return fl.GetValue().(int) > v.GetValue().(int)
|
||||
}
|
||||
|
||||
func TestPriorityInsert(t *testing.T) {
|
||||
pl := New()
|
||||
|
||||
fl := new(FL)
|
||||
fl.SetValue(12)
|
||||
pl.InsertValue(fl)
|
||||
fl = new(FL)
|
||||
fl.SetValue(123)
|
||||
pl.InsertValue(fl)
|
||||
fl = new(FL)
|
||||
fl.SetValue(1233)
|
||||
pl.InsertValue(fl)
|
||||
fl = new(FL)
|
||||
fl.SetValue(1)
|
||||
pl.InsertValue(fl)
|
||||
t.Error(pl.String())
|
||||
}
|
Loading…
Reference in New Issue
Block a user