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