gtimer_timer.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. "time"
  10. "github.com/gogf/gf/v2/container/gtype"
  11. )
  12. // New creates and returns a Timer.
  13. func New(options ...TimerOptions) *Timer {
  14. t := &Timer{
  15. queue: newPriorityQueue(),
  16. status: gtype.NewInt(StatusRunning),
  17. ticks: gtype.NewInt64(),
  18. }
  19. if len(options) > 0 {
  20. t.options = options[0]
  21. if t.options.Interval == 0 {
  22. t.options.Interval = defaultInterval
  23. }
  24. } else {
  25. t.options = DefaultOptions()
  26. }
  27. go t.loop()
  28. return t
  29. }
  30. // Add adds a timing job to the timer, which runs in interval of `interval`.
  31. func (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  32. return t.createEntry(createEntryInput{
  33. Ctx: ctx,
  34. Interval: interval,
  35. Job: job,
  36. IsSingleton: false,
  37. Times: -1,
  38. Status: StatusReady,
  39. })
  40. }
  41. // AddEntry adds a timing job to the timer with detailed parameters.
  42. //
  43. // The parameter `interval` specifies the running interval of the job.
  44. //
  45. // The parameter `singleton` specifies whether the job running in singleton mode.
  46. // There's only one of the same job is allowed running when it's a singleton mode job.
  47. //
  48. // The parameter `times` specifies limit for the job running times, which means the job
  49. // exits if its run times exceeds the `times`.
  50. //
  51. // The parameter `status` specifies the job status when it's firstly added to the timer.
  52. func (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {
  53. return t.createEntry(createEntryInput{
  54. Ctx: ctx,
  55. Interval: interval,
  56. Job: job,
  57. IsSingleton: isSingleton,
  58. Times: times,
  59. Status: status,
  60. })
  61. }
  62. // AddSingleton is a convenience function for add singleton mode job.
  63. func (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  64. return t.createEntry(createEntryInput{
  65. Ctx: ctx,
  66. Interval: interval,
  67. Job: job,
  68. IsSingleton: true,
  69. Times: -1,
  70. Status: StatusReady,
  71. })
  72. }
  73. // AddOnce is a convenience function for adding a job which only runs once and then exits.
  74. func (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  75. return t.createEntry(createEntryInput{
  76. Ctx: ctx,
  77. Interval: interval,
  78. Job: job,
  79. IsSingleton: true,
  80. Times: 1,
  81. Status: StatusReady,
  82. })
  83. }
  84. // AddTimes is a convenience function for adding a job which is limited running times.
  85. func (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {
  86. return t.createEntry(createEntryInput{
  87. Ctx: ctx,
  88. Interval: interval,
  89. Job: job,
  90. IsSingleton: true,
  91. Times: times,
  92. Status: StatusReady,
  93. })
  94. }
  95. // DelayAdd adds a timing job after delay of `delay` duration.
  96. // Also see Add.
  97. func (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  98. t.AddOnce(ctx, delay, func(ctx context.Context) {
  99. t.Add(ctx, interval, job)
  100. })
  101. }
  102. // DelayAddEntry adds a timing job after delay of `delay` duration.
  103. // Also see AddEntry.
  104. func (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {
  105. t.AddOnce(ctx, delay, func(ctx context.Context) {
  106. t.AddEntry(ctx, interval, job, isSingleton, times, status)
  107. })
  108. }
  109. // DelayAddSingleton adds a timing job after delay of `delay` duration.
  110. // Also see AddSingleton.
  111. func (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  112. t.AddOnce(ctx, delay, func(ctx context.Context) {
  113. t.AddSingleton(ctx, interval, job)
  114. })
  115. }
  116. // DelayAddOnce adds a timing job after delay of `delay` duration.
  117. // Also see AddOnce.
  118. func (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  119. t.AddOnce(ctx, delay, func(ctx context.Context) {
  120. t.AddOnce(ctx, interval, job)
  121. })
  122. }
  123. // DelayAddTimes adds a timing job after delay of `delay` duration.
  124. // Also see AddTimes.
  125. func (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {
  126. t.AddOnce(ctx, delay, func(ctx context.Context) {
  127. t.AddTimes(ctx, interval, times, job)
  128. })
  129. }
  130. // Start starts the timer.
  131. func (t *Timer) Start() {
  132. t.status.Set(StatusRunning)
  133. }
  134. // Stop stops the timer.
  135. func (t *Timer) Stop() {
  136. t.status.Set(StatusStopped)
  137. }
  138. // Close closes the timer.
  139. func (t *Timer) Close() {
  140. t.status.Set(StatusClosed)
  141. }
  142. type createEntryInput struct {
  143. Ctx context.Context
  144. Interval time.Duration
  145. Job JobFunc
  146. IsSingleton bool
  147. Times int
  148. Status int
  149. }
  150. // createEntry creates and adds a timing job to the timer.
  151. func (t *Timer) createEntry(in createEntryInput) *Entry {
  152. var (
  153. infinite = false
  154. nextTicks int64
  155. )
  156. if in.Times <= 0 {
  157. infinite = true
  158. }
  159. var (
  160. intervalTicksOfJob = int64(in.Interval / t.options.Interval)
  161. )
  162. if intervalTicksOfJob == 0 {
  163. // If the given interval is lesser than the one of the wheel,
  164. // then sets it to one tick, which means it will be run in one interval.
  165. intervalTicksOfJob = 1
  166. }
  167. if t.options.Quick {
  168. // If the quick mode is enabled, which means it will be run right now.
  169. // Don't need to wait for the first interval.
  170. nextTicks = t.ticks.Val()
  171. } else {
  172. nextTicks = t.ticks.Val() + intervalTicksOfJob
  173. }
  174. var (
  175. entry = &Entry{
  176. job: in.Job,
  177. ctx: in.Ctx,
  178. timer: t,
  179. ticks: intervalTicksOfJob,
  180. times: gtype.NewInt(in.Times),
  181. status: gtype.NewInt(in.Status),
  182. isSingleton: gtype.NewBool(in.IsSingleton),
  183. nextTicks: gtype.NewInt64(nextTicks),
  184. infinite: gtype.NewBool(infinite),
  185. }
  186. )
  187. t.queue.Push(entry, nextTicks)
  188. return entry
  189. }