github.com/gogf/gf/v2@v2.7.4/os/gcron/gcron_cron.go (about) 1 // Copyright GoFrame Author(https://goframe.org). 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/gogf/gf. 6 7 package gcron 8 9 import ( 10 "context" 11 "sync" 12 "time" 13 14 "github.com/gogf/gf/v2/container/garray" 15 "github.com/gogf/gf/v2/container/gmap" 16 "github.com/gogf/gf/v2/container/gtype" 17 "github.com/gogf/gf/v2/os/glog" 18 "github.com/gogf/gf/v2/os/gtimer" 19 ) 20 21 // Cron stores all the cron job entries. 22 type Cron struct { 23 idGen *gtype.Int64 // Used for unique name generation. 24 status *gtype.Int // Timed task status(0: Not Start; 1: Running; 2: Stopped; -1: Closed) 25 entries *gmap.StrAnyMap // All timed task entries. 26 logger glog.ILogger // Logger, it is nil in default. 27 jobWaiter sync.WaitGroup // Graceful shutdown when cron jobs are stopped. 28 } 29 30 // New returns a new Cron object with default settings. 31 func New() *Cron { 32 return &Cron{ 33 idGen: gtype.NewInt64(), 34 status: gtype.NewInt(StatusRunning), 35 entries: gmap.NewStrAnyMap(true), 36 } 37 } 38 39 // SetLogger sets the logger for cron. 40 func (c *Cron) SetLogger(logger glog.ILogger) { 41 c.logger = logger 42 } 43 44 // GetLogger returns the logger in the cron. 45 func (c *Cron) GetLogger() glog.ILogger { 46 return c.logger 47 } 48 49 // AddEntry creates and returns a new Entry object. 50 func (c *Cron) AddEntry( 51 ctx context.Context, 52 pattern string, 53 job JobFunc, 54 times int, 55 isSingleton bool, 56 name ...string, 57 ) (*Entry, error) { 58 var ( 59 entryName = "" 60 infinite = false 61 ) 62 if len(name) > 0 { 63 entryName = name[0] 64 } 65 if times <= 0 { 66 infinite = true 67 } 68 return c.doAddEntry(doAddEntryInput{ 69 Name: entryName, 70 Job: job, 71 Ctx: ctx, 72 Times: times, 73 Pattern: pattern, 74 IsSingleton: isSingleton, 75 Infinite: infinite, 76 }) 77 } 78 79 // Add adds a timed task. 80 // A unique `name` can be bound with the timed task. 81 // It returns and error if the `name` is already used. 82 func (c *Cron) Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { 83 return c.AddEntry(ctx, pattern, job, -1, false, name...) 84 } 85 86 // AddSingleton adds a singleton timed task. 87 // A singleton timed task is that can only be running one single instance at the same time. 88 // A unique `name` can be bound with the timed task. 89 // It returns and error if the `name` is already used. 90 func (c *Cron) AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { 91 return c.AddEntry(ctx, pattern, job, -1, true, name...) 92 } 93 94 // AddTimes adds a timed task which can be run specified times. 95 // A unique `name` can be bound with the timed task. 96 // It returns and error if the `name` is already used. 97 func (c *Cron) AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) { 98 return c.AddEntry(ctx, pattern, job, times, false, name...) 99 } 100 101 // AddOnce adds a timed task which can be run only once. 102 // A unique `name` can be bound with the timed task. 103 // It returns and error if the `name` is already used. 104 func (c *Cron) AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) { 105 return c.AddEntry(ctx, pattern, job, 1, false, name...) 106 } 107 108 // DelayAddEntry adds a timed task after `delay` time. 109 func (c *Cron) DelayAddEntry(ctx context.Context, delay time.Duration, pattern string, job JobFunc, times int, isSingleton bool, name ...string) { 110 gtimer.AddOnce(ctx, delay, func(ctx context.Context) { 111 if _, err := c.AddEntry(ctx, pattern, job, times, isSingleton, name...); err != nil { 112 panic(err) 113 } 114 }) 115 } 116 117 // DelayAdd adds a timed task after `delay` time. 118 func (c *Cron) DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { 119 gtimer.AddOnce(ctx, delay, func(ctx context.Context) { 120 if _, err := c.Add(ctx, pattern, job, name...); err != nil { 121 panic(err) 122 } 123 }) 124 } 125 126 // DelayAddSingleton adds a singleton timed task after `delay` time. 127 func (c *Cron) DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { 128 gtimer.AddOnce(ctx, delay, func(ctx context.Context) { 129 if _, err := c.AddSingleton(ctx, pattern, job, name...); err != nil { 130 panic(err) 131 } 132 }) 133 } 134 135 // DelayAddOnce adds a timed task after `delay` time. 136 // This timed task can be run only once. 137 func (c *Cron) DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) { 138 gtimer.AddOnce(ctx, delay, func(ctx context.Context) { 139 if _, err := c.AddOnce(ctx, pattern, job, name...); err != nil { 140 panic(err) 141 } 142 }) 143 } 144 145 // DelayAddTimes adds a timed task after `delay` time. 146 // This timed task can be run specified times. 147 func (c *Cron) DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) { 148 gtimer.AddOnce(ctx, delay, func(ctx context.Context) { 149 if _, err := c.AddTimes(ctx, pattern, times, job, name...); err != nil { 150 panic(err) 151 } 152 }) 153 } 154 155 // Search returns a scheduled task with the specified `name`. 156 // It returns nil if not found. 157 func (c *Cron) Search(name string) *Entry { 158 if v := c.entries.Get(name); v != nil { 159 return v.(*Entry) 160 } 161 return nil 162 } 163 164 // Start starts running the specified timed task named `name`. 165 // If no`name` specified, it starts the entire cron. 166 func (c *Cron) Start(name ...string) { 167 if len(name) > 0 { 168 for _, v := range name { 169 if entry := c.Search(v); entry != nil { 170 entry.Start() 171 } 172 } 173 } else { 174 c.status.Set(StatusReady) 175 } 176 } 177 178 // Stop stops running the specified timed task named `name`. 179 // If no`name` specified, it stops the entire cron. 180 func (c *Cron) Stop(name ...string) { 181 if len(name) > 0 { 182 for _, v := range name { 183 if entry := c.Search(v); entry != nil { 184 entry.Stop() 185 } 186 } 187 } else { 188 c.status.Set(StatusStopped) 189 } 190 } 191 192 // StopGracefully Blocks and waits all current running jobs done. 193 func (c *Cron) StopGracefully() { 194 c.status.Set(StatusStopped) 195 c.jobWaiter.Wait() 196 } 197 198 // Remove deletes scheduled task which named `name`. 199 func (c *Cron) Remove(name string) { 200 if v := c.entries.Get(name); v != nil { 201 v.(*Entry).Close() 202 } 203 } 204 205 // Close stops and closes current cron. 206 func (c *Cron) Close() { 207 c.status.Set(StatusClosed) 208 } 209 210 // Size returns the size of the timed tasks. 211 func (c *Cron) Size() int { 212 return c.entries.Size() 213 } 214 215 // Entries return all timed tasks as slice(order by registered time asc). 216 func (c *Cron) Entries() []*Entry { 217 array := garray.NewSortedArraySize(c.entries.Size(), func(v1, v2 interface{}) int { 218 entry1 := v1.(*Entry) 219 entry2 := v2.(*Entry) 220 if entry1.RegisterTime.Nanosecond() > entry2.RegisterTime.Nanosecond() { 221 return 1 222 } 223 return -1 224 }, true) 225 c.entries.RLockFunc(func(m map[string]interface{}) { 226 for _, v := range m { 227 array.Add(v.(*Entry)) 228 } 229 }) 230 entries := make([]*Entry, array.Len()) 231 array.RLockFunc(func(array []interface{}) { 232 for k, v := range array { 233 entries[k] = v.(*Entry) 234 } 235 }) 236 return entries 237 }