github.com/gogf/gf/v2@v2.7.4/os/gtimer/gtimer_entry.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 12 "github.com/gogf/gf/v2/errors/gcode" 13 14 "github.com/gogf/gf/v2/container/gtype" 15 "github.com/gogf/gf/v2/errors/gerror" 16 ) 17 18 // Entry is the timing job. 19 type Entry struct { 20 job JobFunc // The job function. 21 ctx context.Context // The context for the job, for READ ONLY. 22 timer *Timer // Belonged timer. 23 ticks int64 // The job runs every tick. 24 times *gtype.Int // Limit running times. 25 status *gtype.Int // Job status. 26 isSingleton *gtype.Bool // Singleton mode. 27 nextTicks *gtype.Int64 // Next run ticks of the job. 28 infinite *gtype.Bool // No times limit. 29 } 30 31 // JobFunc is the timing called job function in timer. 32 type JobFunc = func(ctx context.Context) 33 34 // Status returns the status of the job. 35 func (entry *Entry) Status() int { 36 return entry.status.Val() 37 } 38 39 // Run runs the timer job asynchronously. 40 func (entry *Entry) Run() { 41 if !entry.infinite.Val() { 42 leftRunningTimes := entry.times.Add(-1) 43 // It checks its running times exceeding. 44 if leftRunningTimes < 0 { 45 entry.status.Set(StatusClosed) 46 return 47 } 48 } 49 go entry.callJobFunc() 50 } 51 52 // callJobFunc executes the job function in entry. 53 func (entry *Entry) callJobFunc() { 54 defer func() { 55 if exception := recover(); exception != nil { 56 if exception != panicExit { 57 if v, ok := exception.(error); ok && gerror.HasStack(v) { 58 panic(v) 59 } else { 60 panic(gerror.NewCodef(gcode.CodeInternalPanic, "exception recovered: %+v", exception)) 61 } 62 } else { 63 entry.Close() 64 return 65 } 66 } 67 if entry.Status() == StatusRunning { 68 entry.SetStatus(StatusReady) 69 } 70 }() 71 entry.job(entry.ctx) 72 } 73 74 // doCheckAndRunByTicks checks the if job can run in given timer ticks, 75 // it runs asynchronously if the given `currentTimerTicks` meets or else 76 // it increments its ticks and waits for next running check. 77 func (entry *Entry) doCheckAndRunByTicks(currentTimerTicks int64) { 78 // Ticks check. 79 if currentTimerTicks < entry.nextTicks.Val() { 80 return 81 } 82 entry.nextTicks.Set(currentTimerTicks + entry.ticks) 83 // Perform job checking. 84 switch entry.status.Val() { 85 case StatusRunning: 86 if entry.IsSingleton() { 87 return 88 } 89 case StatusReady: 90 if !entry.status.Cas(StatusReady, StatusRunning) { 91 return 92 } 93 case StatusStopped: 94 return 95 case StatusClosed: 96 return 97 } 98 // Perform job running. 99 entry.Run() 100 } 101 102 // SetStatus custom sets the status for the job. 103 func (entry *Entry) SetStatus(status int) int { 104 return entry.status.Set(status) 105 } 106 107 // Start starts the job. 108 func (entry *Entry) Start() { 109 entry.status.Set(StatusReady) 110 } 111 112 // Stop stops the job. 113 func (entry *Entry) Stop() { 114 entry.status.Set(StatusStopped) 115 } 116 117 // Close closes the job, and then it will be removed from the timer. 118 func (entry *Entry) Close() { 119 entry.status.Set(StatusClosed) 120 } 121 122 // Reset resets the job, which resets its ticks for next running. 123 func (entry *Entry) Reset() { 124 entry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks) 125 } 126 127 // IsSingleton checks and returns whether the job in singleton mode. 128 func (entry *Entry) IsSingleton() bool { 129 return entry.isSingleton.Val() 130 } 131 132 // SetSingleton sets the job singleton mode. 133 func (entry *Entry) SetSingleton(enabled bool) { 134 entry.isSingleton.Set(enabled) 135 } 136 137 // Job returns the job function of this job. 138 func (entry *Entry) Job() JobFunc { 139 return entry.job 140 } 141 142 // Ctx returns the initialized context of this job. 143 func (entry *Entry) Ctx() context.Context { 144 return entry.ctx 145 } 146 147 // SetTimes sets the limit running times for the job. 148 func (entry *Entry) SetTimes(times int) { 149 entry.times.Set(times) 150 entry.infinite.Set(false) 151 }