TODO: 修复时间控制的bug

This commit is contained in:
eson 2018-12-21 04:18:40 +08:00
parent 19a4034928
commit 0dce1192d2
5 changed files with 193 additions and 230 deletions

86
base.go Normal file
View 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)
}
}

View File

@ -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)
}
}

View File

@ -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() {

View File

@ -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)
}

View File

@ -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())
}