github.com/gogf/gf/v2@v2.7.4/os/gtimer/gtimer_timer.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 gtimer 8 9 import ( 10 "context" 11 "time" 12 13 "github.com/gogf/gf/v2/container/gtype" 14 ) 15 16 // New creates and returns a Timer. 17 func New(options ...TimerOptions) *Timer { 18 t := &Timer{ 19 queue: newPriorityQueue(), 20 status: gtype.NewInt(StatusRunning), 21 ticks: gtype.NewInt64(), 22 } 23 if len(options) > 0 { 24 t.options = options[0] 25 if t.options.Interval == 0 { 26 t.options.Interval = defaultInterval 27 } 28 } else { 29 t.options = DefaultOptions() 30 } 31 go t.loop() 32 return t 33 } 34 35 // Add adds a timing job to the timer, which runs in interval of `interval`. 36 func (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry { 37 return t.createEntry(createEntryInput{ 38 Ctx: ctx, 39 Interval: interval, 40 Job: job, 41 IsSingleton: false, 42 Times: -1, 43 Status: StatusReady, 44 }) 45 } 46 47 // AddEntry adds a timing job to the timer with detailed parameters. 48 // 49 // The parameter `interval` specifies the running interval of the job. 50 // 51 // The parameter `singleton` specifies whether the job running in singleton mode. 52 // There's only one of the same job is allowed running when it's a singleton mode job. 53 // 54 // The parameter `times` specifies limit for the job running times, which means the job 55 // exits if its run times exceeds the `times`. 56 // 57 // The parameter `status` specifies the job status when it's firstly added to the timer. 58 func (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry { 59 return t.createEntry(createEntryInput{ 60 Ctx: ctx, 61 Interval: interval, 62 Job: job, 63 IsSingleton: isSingleton, 64 Times: times, 65 Status: status, 66 }) 67 } 68 69 // AddSingleton is a convenience function for add singleton mode job. 70 func (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry { 71 return t.createEntry(createEntryInput{ 72 Ctx: ctx, 73 Interval: interval, 74 Job: job, 75 IsSingleton: true, 76 Times: -1, 77 Status: StatusReady, 78 }) 79 } 80 81 // AddOnce is a convenience function for adding a job which only runs once and then exits. 82 func (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry { 83 return t.createEntry(createEntryInput{ 84 Ctx: ctx, 85 Interval: interval, 86 Job: job, 87 IsSingleton: true, 88 Times: 1, 89 Status: StatusReady, 90 }) 91 } 92 93 // AddTimes is a convenience function for adding a job which is limited running times. 94 func (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry { 95 return t.createEntry(createEntryInput{ 96 Ctx: ctx, 97 Interval: interval, 98 Job: job, 99 IsSingleton: true, 100 Times: times, 101 Status: StatusReady, 102 }) 103 } 104 105 // DelayAdd adds a timing job after delay of `delay` duration. 106 // Also see Add. 107 func (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { 108 t.AddOnce(ctx, delay, func(ctx context.Context) { 109 t.Add(ctx, interval, job) 110 }) 111 } 112 113 // DelayAddEntry adds a timing job after delay of `delay` duration. 114 // Also see AddEntry. 115 func (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) { 116 t.AddOnce(ctx, delay, func(ctx context.Context) { 117 t.AddEntry(ctx, interval, job, isSingleton, times, status) 118 }) 119 } 120 121 // DelayAddSingleton adds a timing job after delay of `delay` duration. 122 // Also see AddSingleton. 123 func (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { 124 t.AddOnce(ctx, delay, func(ctx context.Context) { 125 t.AddSingleton(ctx, interval, job) 126 }) 127 } 128 129 // DelayAddOnce adds a timing job after delay of `delay` duration. 130 // Also see AddOnce. 131 func (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) { 132 t.AddOnce(ctx, delay, func(ctx context.Context) { 133 t.AddOnce(ctx, interval, job) 134 }) 135 } 136 137 // DelayAddTimes adds a timing job after delay of `delay` duration. 138 // Also see AddTimes. 139 func (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) { 140 t.AddOnce(ctx, delay, func(ctx context.Context) { 141 t.AddTimes(ctx, interval, times, job) 142 }) 143 } 144 145 // Start starts the timer. 146 func (t *Timer) Start() { 147 t.status.Set(StatusRunning) 148 } 149 150 // Stop stops the timer. 151 func (t *Timer) Stop() { 152 t.status.Set(StatusStopped) 153 } 154 155 // Close closes the timer. 156 func (t *Timer) Close() { 157 t.status.Set(StatusClosed) 158 } 159 160 type createEntryInput struct { 161 Ctx context.Context 162 Interval time.Duration 163 Job JobFunc 164 IsSingleton bool 165 Times int 166 Status int 167 } 168 169 // createEntry creates and adds a timing job to the timer. 170 func (t *Timer) createEntry(in createEntryInput) *Entry { 171 var ( 172 infinite = false 173 nextTicks int64 174 ) 175 if in.Times <= 0 { 176 infinite = true 177 } 178 var ( 179 intervalTicksOfJob = int64(in.Interval / t.options.Interval) 180 ) 181 if intervalTicksOfJob == 0 { 182 // If the given interval is lesser than the one of the wheel, 183 // then sets it to one tick, which means it will be run in one interval. 184 intervalTicksOfJob = 1 185 } 186 if t.options.Quick { 187 // If the quick mode is enabled, which means it will be run right now. 188 // Don't need to wait for the first interval. 189 nextTicks = t.ticks.Val() 190 } else { 191 nextTicks = t.ticks.Val() + intervalTicksOfJob 192 } 193 var ( 194 entry = &Entry{ 195 job: in.Job, 196 ctx: in.Ctx, 197 timer: t, 198 ticks: intervalTicksOfJob, 199 times: gtype.NewInt(in.Times), 200 status: gtype.NewInt(in.Status), 201 isSingleton: gtype.NewBool(in.IsSingleton), 202 nextTicks: gtype.NewInt64(nextTicks), 203 infinite: gtype.NewBool(infinite), 204 } 205 ) 206 t.queue.Push(entry, nextTicks) 207 return entry 208 }