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