3f5b5c1e01
Extract monitoring recovery/inspection workers and schedule dispatch into a dedicated scheduler process. Add worker-generate process for article generation and template-assist queue consumption. Introduce shared/schedule runtime for cron-based worker lifecycle management. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
1.3 KiB
Go
69 lines
1.3 KiB
Go
package schedule
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
cron "github.com/robfig/cron/v3"
|
|
)
|
|
|
|
var cronParser = cron.NewParser(
|
|
cron.SecondOptional |
|
|
cron.Minute |
|
|
cron.Hour |
|
|
cron.Dom |
|
|
cron.Month |
|
|
cron.Dow |
|
|
cron.Descriptor,
|
|
)
|
|
|
|
func Parse(cronExpr string) (cron.Schedule, error) {
|
|
trimmed := strings.TrimSpace(cronExpr)
|
|
if trimmed == "" {
|
|
return nil, fmt.Errorf("cron expression is required")
|
|
}
|
|
|
|
schedule, err := cronParser.Parse(trimmed)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse cron expression %q: %w", trimmed, err)
|
|
}
|
|
return schedule, nil
|
|
}
|
|
|
|
func ComputeNextRun(cronExpr string, startAt, endAt *time.Time, now time.Time) (*time.Time, error) {
|
|
schedule, err := Parse(cronExpr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
notBefore := now.In(time.Local)
|
|
if startAt != nil {
|
|
start := startAt.In(time.Local)
|
|
if start.After(notBefore) {
|
|
notBefore = start
|
|
}
|
|
}
|
|
|
|
next := schedule.Next(notBefore.Add(-time.Nanosecond)).Round(0)
|
|
if next.IsZero() {
|
|
return nil, nil
|
|
}
|
|
if endAt != nil && next.After(endAt.In(time.Local)) {
|
|
return nil, nil
|
|
}
|
|
|
|
return &next, nil
|
|
}
|
|
|
|
func IsRunAllowed(runAt time.Time, startAt, endAt *time.Time) bool {
|
|
runAt = runAt.In(time.Local)
|
|
if startAt != nil && runAt.Before(startAt.In(time.Local)) {
|
|
return false
|
|
}
|
|
if endAt != nil && runAt.After(endAt.In(time.Local)) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|