gtimer_entry.go 3.8 KB

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