overflow_probes/commons/scheduler/Job.go

341 lines
6.9 KiB
Go
Raw Permalink Normal View History

2018-03-26 15:14:19 +00:00
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
}