341 lines
6.9 KiB
Go
341 lines
6.9 KiB
Go
|
package scheduler
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"reflect"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const MAXJOBNUM = 10000
|
||
|
|
||
|
var _location = time.Local
|
||
|
|
||
|
type Job interface {
|
||
|
Do(jobFun interface{}, params ...interface{})
|
||
|
At(t string) Job
|
||
|
NextScheduledTime() time.Time
|
||
|
Second() (job Job)
|
||
|
Seconds() (job Job)
|
||
|
Minute() (job Job)
|
||
|
Minutes() (job Job)
|
||
|
Hour() (job Job)
|
||
|
Hours() (job Job)
|
||
|
Day() (job Job)
|
||
|
Days() (job Job)
|
||
|
Monday() (job Job)
|
||
|
Tuesday() (job Job)
|
||
|
Wednesday() (job Job)
|
||
|
Thursday() (job Job)
|
||
|
Friday() (job Job)
|
||
|
Saturday() (job Job)
|
||
|
Sunday() (job Job)
|
||
|
Weeks() (job Job)
|
||
|
|
||
|
shouldRun() bool
|
||
|
run() (result []reflect.Value, err error)
|
||
|
scheduleNextRun()
|
||
|
nextRun() time.Time
|
||
|
jobFunc() string
|
||
|
}
|
||
|
|
||
|
func NewJob(intervel uint64) Job {
|
||
|
return &innerJob{
|
||
|
intervel,
|
||
|
"", "", "",
|
||
|
time.Unix(0, 0),
|
||
|
time.Unix(0, 0), 0,
|
||
|
time.Sunday,
|
||
|
make(map[string]interface{}),
|
||
|
make(map[string]([]interface{})),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type innerJob struct {
|
||
|
// pause interval * unit bettween runs
|
||
|
interval uint64
|
||
|
|
||
|
// the job _jobFunc to run, func[_jobFunc]
|
||
|
_jobFunc string
|
||
|
// time units, ,e.g. 'minutes', 'hours'...
|
||
|
unit string
|
||
|
// optional time at which this job runs
|
||
|
atTime string
|
||
|
|
||
|
// datetime of last run
|
||
|
lastRun time.Time
|
||
|
// datetime of next run
|
||
|
_nextRun time.Time
|
||
|
// cache the period between last an next run
|
||
|
period time.Duration
|
||
|
|
||
|
// Specific day of the week to start on
|
||
|
startDay time.Weekday
|
||
|
|
||
|
// Map for the function task store
|
||
|
funcs map[string]interface{}
|
||
|
|
||
|
// Map for function and params of function
|
||
|
fparams map[string]([]interface{})
|
||
|
}
|
||
|
|
||
|
// True if the job should be run now
|
||
|
func (j *innerJob) shouldRun() bool {
|
||
|
return time.Now().After(j._nextRun)
|
||
|
}
|
||
|
|
||
|
// True if the job should be run now
|
||
|
func (j *innerJob) nextRun() time.Time {
|
||
|
return j._nextRun
|
||
|
}
|
||
|
|
||
|
// True if the job should be run now
|
||
|
func (j *innerJob) jobFunc() string {
|
||
|
return j._jobFunc
|
||
|
}
|
||
|
|
||
|
//Run the job and immediately reschedule it
|
||
|
func (j *innerJob) run() (result []reflect.Value, err error) {
|
||
|
f := reflect.ValueOf(j.funcs[j._jobFunc])
|
||
|
params := j.fparams[j._jobFunc]
|
||
|
if len(params) != f.Type().NumIn() {
|
||
|
err = errors.New("the number of param is not adapted")
|
||
|
return
|
||
|
}
|
||
|
in := make([]reflect.Value, len(params))
|
||
|
for k, param := range params {
|
||
|
in[k] = reflect.ValueOf(param)
|
||
|
}
|
||
|
result = f.Call(in)
|
||
|
j.lastRun = time.Now()
|
||
|
j.scheduleNextRun()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (j *innerJob) Do(jobFun interface{}, params ...interface{}) {
|
||
|
typ := reflect.TypeOf(jobFun)
|
||
|
if typ.Kind() != reflect.Func {
|
||
|
panic("only function can be schedule into the job queue.")
|
||
|
}
|
||
|
|
||
|
fname := getFunctionName(jobFun)
|
||
|
j.funcs[fname] = jobFun
|
||
|
j.fparams[fname] = params
|
||
|
j._jobFunc = fname
|
||
|
//schedule the next run
|
||
|
j.scheduleNextRun()
|
||
|
}
|
||
|
|
||
|
// s.Every(1).Day().At("10:30").Do(task)
|
||
|
// s.Every(1).Monday().At("10:30").Do(task)
|
||
|
func (j *innerJob) At(t string) Job {
|
||
|
hour, min, err := formatTime(t)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
// time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||
|
mock := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), int(hour), int(min), 0, 0, _location)
|
||
|
|
||
|
if j.unit == "days" {
|
||
|
if time.Now().After(mock) {
|
||
|
j.lastRun = mock
|
||
|
} else {
|
||
|
j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, hour, min, 0, 0, _location)
|
||
|
}
|
||
|
} else if j.unit == "weeks" {
|
||
|
if j.startDay != time.Now().Weekday() || (time.Now().After(mock) && j.startDay == time.Now().Weekday()) {
|
||
|
i := mock.Weekday() - j.startDay
|
||
|
if i < 0 {
|
||
|
i = 7 + i
|
||
|
}
|
||
|
j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), hour, min, 0, 0, _location)
|
||
|
} else {
|
||
|
j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-7, hour, min, 0, 0, _location)
|
||
|
}
|
||
|
}
|
||
|
return j
|
||
|
}
|
||
|
|
||
|
//Compute the instant when this job should run next
|
||
|
func (j *innerJob) scheduleNextRun() {
|
||
|
if j.lastRun == time.Unix(0, 0) {
|
||
|
if j.unit == "weeks" {
|
||
|
i := time.Now().Weekday() - j.startDay
|
||
|
if i < 0 {
|
||
|
i = 7 + i
|
||
|
}
|
||
|
j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), 0, 0, 0, 0, _location)
|
||
|
|
||
|
} else {
|
||
|
j.lastRun = time.Now()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if j.period != 0 {
|
||
|
// translate all the units to the Seconds
|
||
|
j._nextRun = j.lastRun.Add(j.period * time.Second)
|
||
|
} else {
|
||
|
switch j.unit {
|
||
|
case "minutes":
|
||
|
j.period = time.Duration(j.interval * 60)
|
||
|
break
|
||
|
case "hours":
|
||
|
j.period = time.Duration(j.interval * 60 * 60)
|
||
|
break
|
||
|
case "days":
|
||
|
j.period = time.Duration(j.interval * 60 * 60 * 24)
|
||
|
break
|
||
|
case "weeks":
|
||
|
j.period = time.Duration(j.interval * 60 * 60 * 24 * 7)
|
||
|
break
|
||
|
case "seconds":
|
||
|
j.period = time.Duration(j.interval)
|
||
|
}
|
||
|
j._nextRun = j.lastRun.Add(j.period * time.Second)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NextScheduledTime returns the time of when this job is to run next
|
||
|
func (j *innerJob) NextScheduledTime() time.Time {
|
||
|
return j._nextRun
|
||
|
}
|
||
|
|
||
|
// the follow functions set the job's unit with seconds,minutes,hours...
|
||
|
|
||
|
// Set the unit with second
|
||
|
func (j *innerJob) Second() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
job = j.Seconds()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the unit with seconds
|
||
|
func (j *innerJob) Seconds() (job Job) {
|
||
|
j.unit = "seconds"
|
||
|
return j
|
||
|
}
|
||
|
|
||
|
// Set the unit with minute, which interval is 1
|
||
|
func (j *innerJob) Minute() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
job = j.Minutes()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//set the unit with minute
|
||
|
func (j *innerJob) Minutes() (job Job) {
|
||
|
j.unit = "minutes"
|
||
|
return j
|
||
|
}
|
||
|
|
||
|
//set the unit with hour, which interval is 1
|
||
|
func (j *innerJob) Hour() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
job = j.Hours()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the unit with hours
|
||
|
func (j *innerJob) Hours() (job Job) {
|
||
|
j.unit = "hours"
|
||
|
return j
|
||
|
}
|
||
|
|
||
|
// Set the job's unit with day, which interval is 1
|
||
|
func (j *innerJob) Day() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
job = j.Days()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the job's unit with days
|
||
|
func (j *innerJob) Days() Job {
|
||
|
j.unit = "days"
|
||
|
return j
|
||
|
}
|
||
|
|
||
|
// s.Every(1).Monday().Do(task)
|
||
|
// Set the start day with Monday
|
||
|
func (j *innerJob) Monday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 1
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day with Tuesday
|
||
|
func (j *innerJob) Tuesday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 2
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day woth Wednesday
|
||
|
func (j *innerJob) Wednesday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 3
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day with thursday
|
||
|
func (j *innerJob) Thursday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 4
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day with friday
|
||
|
func (j *innerJob) Friday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 5
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day with saturday
|
||
|
func (j *innerJob) Saturday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 6
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Set the start day with sunday
|
||
|
func (j *innerJob) Sunday() (job Job) {
|
||
|
if j.interval != 1 {
|
||
|
panic("")
|
||
|
}
|
||
|
j.startDay = 0
|
||
|
job = j.Weeks()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//Set the units as weeks
|
||
|
func (j *innerJob) Weeks() Job {
|
||
|
j.unit = "weeks"
|
||
|
return j
|
||
|
}
|