gtimer_timer.go 5.6 KB

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