github.com/zhongdalu/gf@v1.0.0/g/os/gcron/gcron_entry.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 package gcron 8 9 import ( 10 "github.com/zhongdalu/gf/g/container/gtype" 11 "github.com/zhongdalu/gf/g/os/glog" 12 "github.com/zhongdalu/gf/g/os/gtimer" 13 "github.com/zhongdalu/gf/g/util/gconv" 14 "reflect" 15 "runtime" 16 "time" 17 ) 18 19 // Timed task entry. 20 type Entry struct { 21 cron *Cron // Cron object belonged to. 22 entry *gtimer.Entry // Associated gtimer.Entry. 23 schedule *cronSchedule // Timed schedule object. 24 jobName string // Callback function name(address info). 25 times *gtype.Int // Running times limit. 26 Name string // Entry name. 27 Job func() `json:"-"` // Callback function. 28 Time time.Time // Registered time. 29 } 30 31 // addEntry creates and returns a new Entry object. 32 // Param <job> is the callback function for timed task execution. 33 // Param <singleton> specifies whether timed task executing in singleton mode. 34 // Param <name> names this entry for manual control. 35 func (c *Cron) addEntry(pattern string, job func(), singleton bool, name ...string) (*Entry, error) { 36 schedule, err := newSchedule(pattern) 37 if err != nil { 38 return nil, err 39 } 40 // No limit for <times>, for gtimer checking scheduling every second. 41 entry := &Entry{ 42 cron: c, 43 schedule: schedule, 44 jobName: runtime.FuncForPC(reflect.ValueOf(job).Pointer()).Name(), 45 times: gtype.NewInt(gDEFAULT_TIMES), 46 Job: job, 47 Time: time.Now(), 48 } 49 if len(name) > 0 { 50 entry.Name = name[0] 51 } else { 52 entry.Name = "gcron-" + gconv.String(c.idGen.Add(1)) 53 } 54 // When you add a scheduled task, you cannot allow it to run. 55 // It cannot start running when added to gtimer. 56 // It should start running after the entry is added to the entries map, 57 // to avoid the task from running during adding where the entries 58 // does not have the entry information, which might cause panic. 59 entry.entry = gtimer.AddEntry(time.Second, entry.check, singleton, -1, gtimer.STATUS_STOPPED) 60 c.entries.Set(entry.Name, entry) 61 entry.entry.Start() 62 return entry, nil 63 } 64 65 // IsSingleton return whether this entry is a singleton timed task. 66 func (entry *Entry) IsSingleton() bool { 67 return entry.entry.IsSingleton() 68 } 69 70 // SetSingleton sets the entry running in singleton mode. 71 func (entry *Entry) SetSingleton(enabled bool) { 72 entry.entry.SetSingleton(true) 73 } 74 75 // SetTimes sets the times which the entry can run. 76 func (entry *Entry) SetTimes(times int) { 77 entry.times.Set(times) 78 } 79 80 // Status returns the status of entry. 81 func (entry *Entry) Status() int { 82 return entry.entry.Status() 83 } 84 85 // SetStatus sets the status of the entry. 86 func (entry *Entry) SetStatus(status int) int { 87 return entry.entry.SetStatus(status) 88 } 89 90 // Start starts running the entry. 91 func (entry *Entry) Start() { 92 entry.entry.Start() 93 } 94 95 // Stop stops running the entry. 96 func (entry *Entry) Stop() { 97 entry.entry.Stop() 98 } 99 100 // Close stops and removes the entry from cron. 101 func (entry *Entry) Close() { 102 entry.cron.entries.Remove(entry.Name) 103 entry.entry.Close() 104 } 105 106 // Timed task check execution. 107 // The running times limits feature is implemented by gcron.Entry and cannot be implemented by gtimer.Entry. 108 // gcron.Entry relies on gtimer to implement a scheduled task check for gcron.Entry per second. 109 func (entry *Entry) check() { 110 if entry.schedule.meet(time.Now()) { 111 path := entry.cron.GetLogPath() 112 level := entry.cron.GetLogLevel() 113 switch entry.cron.status.Val() { 114 case STATUS_STOPPED: 115 return 116 117 case STATUS_CLOSED: 118 glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s removed", entry.Name, entry.schedule.pattern, entry.jobName) 119 entry.Close() 120 121 case STATUS_READY: 122 fallthrough 123 case STATUS_RUNNING: 124 // Running times check. 125 times := entry.times.Add(-1) 126 if times <= 0 { 127 if entry.entry.SetStatus(STATUS_CLOSED) == STATUS_CLOSED || times < 0 { 128 return 129 } 130 } 131 if times < 2000000000 && times > 1000000000 { 132 entry.times.Set(gDEFAULT_TIMES) 133 } 134 glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s start", entry.Name, entry.schedule.pattern, entry.jobName) 135 defer func() { 136 if err := recover(); err != nil { 137 glog.Path(path).Level(level).Errorf("[gcron] %s(%s) %s end with error: %v", entry.Name, entry.schedule.pattern, entry.jobName, err) 138 } else { 139 glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s end", entry.Name, entry.schedule.pattern, entry.jobName) 140 } 141 if entry.entry.Status() == STATUS_CLOSED { 142 entry.Close() 143 } 144 }() 145 entry.Job() 146 147 } 148 } 149 }