gtimer_entry.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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/container/gtype"
  10. "github.com/gogf/gf/v2/errors/gerror"
  11. )
  12. // Entry is the timing job.
  13. type Entry struct {
  14. job JobFunc // The job function.
  15. ctx context.Context // The context for the job, for READ ONLY.
  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. isSingleton *gtype.Bool // Singleton mode.
  21. nextTicks *gtype.Int64 // Next run ticks of the job.
  22. infinite *gtype.Bool // No times limit.
  23. }
  24. // JobFunc is the timing called job function in timer.
  25. type JobFunc = func(ctx context.Context)
  26. // Status returns the status of the job.
  27. func (entry *Entry) Status() int {
  28. return entry.status.Val()
  29. }
  30. // Run runs the timer job asynchronously.
  31. func (entry *Entry) Run() {
  32. if !entry.infinite.Val() {
  33. leftRunningTimes := entry.times.Add(-1)
  34. // It checks its running times exceeding.
  35. if leftRunningTimes < 0 {
  36. entry.status.Set(StatusClosed)
  37. return
  38. }
  39. }
  40. go func() {
  41. defer func() {
  42. if exception := recover(); exception != nil {
  43. if exception != panicExit {
  44. if v, ok := exception.(error); ok && gerror.HasStack(v) {
  45. panic(v)
  46. } else {
  47. panic(gerror.Newf(`exception recovered: %+v`, exception))
  48. }
  49. } else {
  50. entry.Close()
  51. return
  52. }
  53. }
  54. if entry.Status() == StatusRunning {
  55. entry.SetStatus(StatusReady)
  56. }
  57. }()
  58. entry.job(entry.ctx)
  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. // SetStatus custom sets the status for the job.
  89. func (entry *Entry) SetStatus(status int) int {
  90. return entry.status.Set(status)
  91. }
  92. // Start starts the job.
  93. func (entry *Entry) Start() {
  94. entry.status.Set(StatusReady)
  95. }
  96. // Stop stops the job.
  97. func (entry *Entry) Stop() {
  98. entry.status.Set(StatusStopped)
  99. }
  100. // Close closes the job, and then it will be removed from the timer.
  101. func (entry *Entry) Close() {
  102. entry.status.Set(StatusClosed)
  103. }
  104. // Reset resets the job, which resets its ticks for next running.
  105. func (entry *Entry) Reset() {
  106. entry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks)
  107. }
  108. // IsSingleton checks and returns whether the job in singleton mode.
  109. func (entry *Entry) IsSingleton() bool {
  110. return entry.isSingleton.Val()
  111. }
  112. // SetSingleton sets the job singleton mode.
  113. func (entry *Entry) SetSingleton(enabled bool) {
  114. entry.isSingleton.Set(enabled)
  115. }
  116. // Job returns the job function of this job.
  117. func (entry *Entry) Job() JobFunc {
  118. return entry.job
  119. }
  120. // Ctx returns the initialized context of this job.
  121. func (entry *Entry) Ctx() context.Context {
  122. return entry.ctx
  123. }
  124. // SetTimes sets the limit running times for the job.
  125. func (entry *Entry) SetTimes(times int) {
  126. entry.times.Set(times)
  127. entry.infinite.Set(false)
  128. }