cleaner.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package cache
  2. import (
  3. "fmt"
  4. "time"
  5. "git.i2edu.net/i2/go-zero/core/collection"
  6. "git.i2edu.net/i2/go-zero/core/logx"
  7. "git.i2edu.net/i2/go-zero/core/proc"
  8. "git.i2edu.net/i2/go-zero/core/stat"
  9. "git.i2edu.net/i2/go-zero/core/stringx"
  10. "git.i2edu.net/i2/go-zero/core/threading"
  11. )
  12. const (
  13. timingWheelSlots = 300
  14. cleanWorkers = 5
  15. taskKeyLen = 8
  16. )
  17. var (
  18. timingWheel *collection.TimingWheel
  19. taskRunner = threading.NewTaskRunner(cleanWorkers)
  20. )
  21. type delayTask struct {
  22. delay time.Duration
  23. task func() error
  24. keys []string
  25. }
  26. func init() {
  27. var err error
  28. timingWheel, err = collection.NewTimingWheel(time.Second, timingWheelSlots, clean)
  29. logx.Must(err)
  30. proc.AddShutdownListener(func() {
  31. timingWheel.Drain(clean)
  32. })
  33. }
  34. // AddCleanTask adds a clean task on given keys.
  35. func AddCleanTask(task func() error, keys ...string) {
  36. timingWheel.SetTimer(stringx.Randn(taskKeyLen), delayTask{
  37. delay: time.Second,
  38. task: task,
  39. keys: keys,
  40. }, time.Second)
  41. }
  42. func clean(key, value interface{}) {
  43. taskRunner.Schedule(func() {
  44. dt := value.(delayTask)
  45. err := dt.task()
  46. if err == nil {
  47. return
  48. }
  49. next, ok := nextDelay(dt.delay)
  50. if ok {
  51. dt.delay = next
  52. timingWheel.SetTimer(key, dt, next)
  53. } else {
  54. msg := fmt.Sprintf("retried but failed to clear cache with keys: %q, error: %v",
  55. formatKeys(dt.keys), err)
  56. logx.Error(msg)
  57. stat.Report(msg)
  58. }
  59. })
  60. }
  61. func nextDelay(delay time.Duration) (time.Duration, bool) {
  62. switch delay {
  63. case time.Second:
  64. return time.Second * 5, true
  65. case time.Second * 5:
  66. return time.Minute, true
  67. case time.Minute:
  68. return time.Minute * 5, true
  69. case time.Minute * 5:
  70. return time.Hour, true
  71. default:
  72. return 0, false
  73. }
  74. }