gtimer.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 implements timer for interval/delayed jobs running and management.
  7. //
  8. // This package is designed for management for millions of timing jobs. The differences
  9. // between gtimer and gcron are as follows:
  10. // 1. package gcron is implemented based on package gtimer.
  11. // 2. gtimer is designed for high performance and for millions of timing jobs.
  12. // 3. gcron supports configuration pattern grammar like linux crontab, which is more manually
  13. // readable.
  14. // 4. gtimer's benchmark OP is measured in nanoseconds, and gcron's benchmark OP is measured
  15. // in microseconds.
  16. //
  17. // ALSO VERY NOTE the common delay of the timer: https://github.com/golang/go/issues/14410
  18. package gtimer
  19. import (
  20. "context"
  21. "strconv"
  22. "sync"
  23. "time"
  24. "github.com/gogf/gf/v2/container/gtype"
  25. "github.com/gogf/gf/v2/errors/gcode"
  26. "github.com/gogf/gf/v2/errors/gerror"
  27. "github.com/gogf/gf/v2/internal/command"
  28. )
  29. // Timer is the timer manager, which uses ticks to calculate the timing interval.
  30. type Timer struct {
  31. mu sync.RWMutex
  32. queue *priorityQueue // queue is a priority queue based on heap structure.
  33. status *gtype.Int // status is the current timer status.
  34. ticks *gtype.Int64 // ticks is the proceeded interval number by the timer.
  35. options TimerOptions // timer options is used for timer configuration.
  36. }
  37. // TimerOptions is the configuration object for Timer.
  38. type TimerOptions struct {
  39. Interval time.Duration // (optional) Interval is the underlying rolling interval tick of the timer.
  40. Quick bool // Quick is used for quick timer, which means the timer will not wait for the first interval to be elapsed.
  41. }
  42. // internalPanic is the custom panic for internal usage.
  43. type internalPanic string
  44. const (
  45. StatusReady = 0 // Job or Timer is ready for running.
  46. StatusRunning = 1 // Job or Timer is already running.
  47. StatusStopped = 2 // Job or Timer is stopped.
  48. StatusClosed = -1 // Job or Timer is closed and waiting to be deleted.
  49. panicExit internalPanic = "exit" // panicExit is used for custom job exit with panic.
  50. defaultTimerInterval = "100" // defaultTimerInterval is the default timer interval in milliseconds.
  51. // commandEnvKeyForInterval is the key for command argument or environment configuring default interval duration for timer.
  52. commandEnvKeyForInterval = "gf.gtimer.interval"
  53. )
  54. var (
  55. defaultInterval = getDefaultInterval()
  56. defaultTimer = New()
  57. )
  58. func getDefaultInterval() time.Duration {
  59. interval := command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval)
  60. n, err := strconv.Atoi(interval)
  61. if err != nil {
  62. panic(gerror.WrapCodef(
  63. gcode.CodeInvalidConfiguration, err, `error converting string "%s" to int number`,
  64. interval,
  65. ))
  66. }
  67. return time.Duration(n) * time.Millisecond
  68. }
  69. // DefaultOptions creates and returns a default options object for Timer creation.
  70. func DefaultOptions() TimerOptions {
  71. return TimerOptions{
  72. Interval: defaultInterval,
  73. }
  74. }
  75. // SetTimeout runs the job once after duration of `delay`.
  76. // It is like the one in javascript.
  77. func SetTimeout(ctx context.Context, delay time.Duration, job JobFunc) {
  78. AddOnce(ctx, delay, job)
  79. }
  80. // SetInterval runs the job every duration of `delay`.
  81. // It is like the one in javascript.
  82. func SetInterval(ctx context.Context, interval time.Duration, job JobFunc) {
  83. Add(ctx, interval, job)
  84. }
  85. // Add adds a timing job to the default timer, which runs in interval of `interval`.
  86. func Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  87. return defaultTimer.Add(ctx, interval, job)
  88. }
  89. // AddEntry adds a timing job to the default timer with detailed parameters.
  90. //
  91. // The parameter `interval` specifies the running interval of the job.
  92. //
  93. // The parameter `singleton` specifies whether the job running in singleton mode.
  94. // There's only one of the same job is allowed running when its a singleton mode job.
  95. //
  96. // The parameter `times` specifies limit for the job running times, which means the job
  97. // exits if its run times exceeds the `times`.
  98. //
  99. // The parameter `status` specifies the job status when it's firstly added to the timer.
  100. func AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {
  101. return defaultTimer.AddEntry(ctx, interval, job, isSingleton, times, status)
  102. }
  103. // AddSingleton is a convenience function for add singleton mode job.
  104. func AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  105. return defaultTimer.AddSingleton(ctx, interval, job)
  106. }
  107. // AddOnce is a convenience function for adding a job which only runs once and then exits.
  108. func AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
  109. return defaultTimer.AddOnce(ctx, interval, job)
  110. }
  111. // AddTimes is a convenience function for adding a job which is limited running times.
  112. func AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {
  113. return defaultTimer.AddTimes(ctx, interval, times, job)
  114. }
  115. // DelayAdd adds a timing job after delay of `interval` duration.
  116. // Also see Add.
  117. func DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  118. defaultTimer.DelayAdd(ctx, delay, interval, job)
  119. }
  120. // DelayAddEntry adds a timing job after delay of `interval` duration.
  121. // Also see AddEntry.
  122. func DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {
  123. defaultTimer.DelayAddEntry(ctx, delay, interval, job, isSingleton, times, status)
  124. }
  125. // DelayAddSingleton adds a timing job after delay of `interval` duration.
  126. // Also see AddSingleton.
  127. func DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  128. defaultTimer.DelayAddSingleton(ctx, delay, interval, job)
  129. }
  130. // DelayAddOnce adds a timing job after delay of `interval` duration.
  131. // Also see AddOnce.
  132. func DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
  133. defaultTimer.DelayAddOnce(ctx, delay, interval, job)
  134. }
  135. // DelayAddTimes adds a timing job after delay of `interval` duration.
  136. // Also see AddTimes.
  137. func DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {
  138. defaultTimer.DelayAddTimes(ctx, delay, interval, times, job)
  139. }