You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/jasonlvhit/gocron/scheduler.go

254 lines
5.4 KiB

package gocron
import (
"sort"
"time"
)
// Scheduler struct, the only data member is the list of jobs.
// - implements the sort.Interface{} for sorting jobs, by the time nextRun
type Scheduler struct {
jobs [MAXJOBNUM]*Job // Array store jobs
size int // Size of jobs which jobs holding.
loc *time.Location // Location to use when scheduling jobs with specified times
}
var (
defaultScheduler = NewScheduler()
)
// NewScheduler creates a new scheduler
func NewScheduler() *Scheduler {
return &Scheduler{
jobs: [MAXJOBNUM]*Job{},
size: 0,
loc: loc,
}
}
// Jobs returns the list of Jobs from the Scheduler
func (s *Scheduler) Jobs() []*Job {
return s.jobs[:s.size]
}
func (s *Scheduler) Len() int {
return s.size
}
func (s *Scheduler) Swap(i, j int) {
s.jobs[i], s.jobs[j] = s.jobs[j], s.jobs[i]
}
func (s *Scheduler) Less(i, j int) bool {
return s.jobs[j].nextRun.Unix() >= s.jobs[i].nextRun.Unix()
}
// ChangeLoc changes the default time location
func (s *Scheduler) ChangeLoc(newLocation *time.Location) {
s.loc = newLocation
}
// Get the current runnable jobs, which shouldRun is True
func (s *Scheduler) getRunnableJobs() (runningJobs [MAXJOBNUM]*Job, n int) {
runnableJobs := [MAXJOBNUM]*Job{}
n = 0
sort.Sort(s)
for i := 0; i < s.size; i++ {
if s.jobs[i].shouldRun() {
runnableJobs[n] = s.jobs[i]
n++
} else {
break
}
}
return runnableJobs, n
}
// NextRun datetime when the next job should run.
func (s *Scheduler) NextRun() (*Job, time.Time) {
if s.size <= 0 {
return nil, time.Now()
}
sort.Sort(s)
return s.jobs[0], s.jobs[0].nextRun
}
// Every schedule a new periodic job with interval
func (s *Scheduler) Every(interval uint64) *Job {
job := NewJob(interval).Loc(s.loc)
s.jobs[s.size] = job
s.size++
return job
}
// RunPending runs all the jobs that are scheduled to run.
func (s *Scheduler) RunPending() {
runnableJobs, n := s.getRunnableJobs()
if n != 0 {
for i := 0; i < n; i++ {
go runnableJobs[i].run()
runnableJobs[i].lastRun = time.Now()
runnableJobs[i].scheduleNextRun()
}
}
}
// RunAll run all jobs regardless if they are scheduled to run or not
func (s *Scheduler) RunAll() {
s.RunAllwithDelay(0)
}
// RunAllwithDelay runs all jobs with delay seconds
func (s *Scheduler) RunAllwithDelay(d int) {
for i := 0; i < s.size; i++ {
go s.jobs[i].run()
if 0 != d {
time.Sleep(time.Duration(d))
}
}
}
// Remove specific job j by function
func (s *Scheduler) Remove(j interface{}) {
s.removeByCondition(func(someJob *Job) bool {
return someJob.jobFunc == getFunctionName(j)
})
}
// RemoveByRef removes specific job j by reference
func (s *Scheduler) RemoveByRef(j *Job) {
s.removeByCondition(func(someJob *Job) bool {
return someJob == j
})
}
func (s *Scheduler) removeByCondition(shouldRemove func(*Job) bool) {
i := 0
// keep deleting until no more jobs match the criteria
for {
found := false
for ; i < s.size; i++ {
if shouldRemove(s.jobs[i]) {
found = true
break
}
}
if !found {
return
}
for j := (i + 1); j < s.size; j++ {
s.jobs[i] = s.jobs[j]
i++
}
s.size--
s.jobs[s.size] = nil
}
}
// Scheduled checks if specific job j was already added
func (s *Scheduler) Scheduled(j interface{}) bool {
for _, job := range s.jobs {
if job.jobFunc == getFunctionName(j) {
return true
}
}
return false
}
// Clear delete all scheduled jobs
func (s *Scheduler) Clear() {
for i := 0; i < s.size; i++ {
s.jobs[i] = nil
}
s.size = 0
}
// Start all the pending jobs
// Add seconds ticker
func (s *Scheduler) Start() chan bool {
stopped := make(chan bool, 1)
ticker := time.NewTicker(1 * time.Second)
go func() {
for {
select {
case <-ticker.C:
s.RunPending()
case <-stopped:
ticker.Stop()
return
}
}
}()
return stopped
}
// The following methods are shortcuts for not having to
// create a Scheduler instance
// Every schedules a new periodic job running in specific interval
func Every(interval uint64) *Job {
return defaultScheduler.Every(interval)
}
// RunPending run all jobs that are scheduled to run
//
// Please note that it is *intended behavior that run_pending()
// does not run missed jobs*. For example, if you've registered a job
// that should run every minute and you only call run_pending()
// in one hour increments then your job won't be run 60 times in
// between but only once.
func RunPending() {
defaultScheduler.RunPending()
}
// RunAll run all jobs regardless if they are scheduled to run or not.
func RunAll() {
defaultScheduler.RunAll()
}
// RunAllwithDelay run all the jobs with a delay in seconds
//
// A delay of `delay` seconds is added between each job. This can help
// to distribute the system load generated by the jobs more evenly over
// time.
func RunAllwithDelay(d int) {
defaultScheduler.RunAllwithDelay(d)
}
// Start run all jobs that are scheduled to run
func Start() chan bool {
return defaultScheduler.Start()
}
// Clear all scheduled jobs
func Clear() {
defaultScheduler.Clear()
}
// Remove a specific job
func Remove(j interface{}) {
defaultScheduler.Remove(j)
}
// Scheduled checks if specific job j was already added
func Scheduled(j interface{}) bool {
for _, job := range defaultScheduler.jobs {
if job.jobFunc == getFunctionName(j) {
return true
}
}
return false
}
// NextRun gets the next running time
func NextRun() (job *Job, time time.Time) {
return defaultScheduler.NextRun()
}