cleaner.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package cache
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/tal-tech/go-zero/core/collection"
  6. "github.com/tal-tech/go-zero/core/logx"
  7. "github.com/tal-tech/go-zero/core/proc"
  8. "github.com/tal-tech/go-zero/core/stat"
  9. "github.com/tal-tech/go-zero/core/stringx"
  10. "github.com/tal-tech/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. func AddCleanTask(task func() error, keys ...string) {
  35. timingWheel.SetTimer(stringx.Randn(taskKeyLen), delayTask{
  36. delay: time.Second,
  37. task: task,
  38. keys: keys,
  39. }, time.Second)
  40. }
  41. func clean(key, value interface{}) {
  42. taskRunner.Schedule(func() {
  43. dt := value.(delayTask)
  44. err := dt.task()
  45. if err == nil {
  46. return
  47. }
  48. next, ok := nextDelay(dt.delay)
  49. if ok {
  50. dt.delay = next
  51. timingWheel.SetTimer(key, dt, next)
  52. } else {
  53. msg := fmt.Sprintf("retried but failed to clear cache with keys: %q, error: %v",
  54. formatKeys(dt.keys), err)
  55. logx.Error(msg)
  56. stat.Report(msg)
  57. }
  58. })
  59. }
  60. func nextDelay(delay time.Duration) (time.Duration, bool) {
  61. switch delay {
  62. case time.Second:
  63. return time.Second * 5, true
  64. case time.Second * 5:
  65. return time.Minute, true
  66. case time.Minute:
  67. return time.Minute * 5, true
  68. case time.Minute * 5:
  69. return time.Hour, true
  70. default:
  71. return 0, false
  72. }
  73. }