package standby_ctrl import ( "context" "github.com/go-pkgz/cronrange" "go.uber.org/zap" "sync" "time" ) // Cron 时间控制器 func Cron(rootRules []cronrange.Rule, cron string, play func(c context.Context) error) func(c context.Context) error { // 设定默认时间规则 if cron == "" { cron = "* * * *" } rules, err := cronrange.Parse(cron) if err != nil { zap.S().Errorln("解析时间规则异常: ", err) return nil } return func(c context.Context) error { a := make(chan bool) defer close(a) zap.S().Infoln("待机时间控制器") defer zap.S().Infoln("待机时间控制器结束") // 等待组 var waitGroup sync.WaitGroup defer waitGroup.Wait() ticker := time.NewTicker(time.Second) defer ticker.Stop() waitGroup.Add(1) go func() { defer waitGroup.Done() for { select { case <-c.Done(): return case <-ticker.C: if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) { a <- true } else { a <- false } } } }() var cancel context.CancelFunc var m sync.Mutex for { select { case <-c.Done(): if cancel != nil { cancel() cancel = nil } return nil case r := <-a: if r { if ok := m.TryLock(); ok { ctx, cc := context.WithCancel(context.TODO()) cancel = cc waitGroup.Add(1) go func() { defer waitGroup.Done() defer m.Unlock() defer func() { cancel = nil }() err := play(ctx) if err != nil { zap.S().Errorln("执行动作异常: ", err) select { case <-ctx.Done(): return case <-time.After(time.Minute): } } }() } } else if cancel != nil { cancel() cancel = nil } } } } }