cache.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package redis
  2. import (
  3. "context"
  4. "fmt"
  5. "kpt-pasture/config"
  6. "math/rand"
  7. "time"
  8. "gitee.com/xuyiping_admin/pkg/xerr"
  9. "github.com/eko/gocache/cache"
  10. "github.com/eko/gocache/marshaler"
  11. "github.com/eko/gocache/metrics"
  12. "github.com/eko/gocache/store"
  13. redisv7 "github.com/go-redis/redis/v7"
  14. )
  15. func init() {
  16. rand.Seed(time.Now().UnixNano())
  17. }
  18. // Options redis 使用约束
  19. type Options = store.Options
  20. // TTL redis key TTL
  21. func TTL(duration time.Duration) *Options {
  22. return &store.Options{
  23. // 避免集中过期
  24. Expiration: duration + time.Duration(rand.Int31n(100))*time.Second,
  25. }
  26. }
  27. // CacheObject 缓存对象
  28. type CacheObject interface {
  29. CacheKey() string
  30. }
  31. // CacheStoreRedis Redis 缓存实例
  32. //
  33. //go:generate mockgen -destination mock/redismock.go -package redismock kpt_event/service/redis CacheStoreRedis
  34. type CacheStoreRedis interface {
  35. Namespace() string
  36. SetNamespace(string)
  37. // FullKey 返回带命名空间的完整key
  38. FullKey(key string) string
  39. Client() *redisv7.Client
  40. Get(ctx context.Context, Obj CacheObject) (interface{}, error)
  41. BatchGet(ctx context.Context, objects []CacheObject) (map[string]interface{}, error)
  42. Set(ctx context.Context, Obj CacheObject, options *store.Options) error
  43. TTL(ctx context.Context, obj CacheObject) (time.Duration, error)
  44. Delete(ctx context.Context, keys ...interface{}) error
  45. }
  46. func NewCacheStoreRedis(cfg *config.AppConfig) CacheStoreRedis {
  47. return NewCacheStoreRedisEntry(cfg)
  48. }
  49. func NewCacheStoreRedisEntry(cfg *config.AppConfig) *CacheStoreRedisEntry {
  50. client := NewClientLatest(cfg)
  51. redisStore := store.NewRedis(client, nil)
  52. promMetrics := metrics.NewPrometheus(cfg.Name())
  53. cacheManager := cache.NewMetric(promMetrics, cache.New(redisStore))
  54. marshal := marshaler.New(cacheManager)
  55. return &CacheStoreRedisEntry{
  56. client: client,
  57. cacheNamespace: config.Options().CacheNameSpace(),
  58. cacheMarshal: marshal,
  59. }
  60. }
  61. type CacheStoreRedisEntry struct {
  62. client *redisv7.Client
  63. cacheNamespace string
  64. cacheMarshal *marshaler.Marshaler
  65. }
  66. func (entry *CacheStoreRedisEntry) fullKey(key string) string {
  67. return fmt.Sprintf("%s:%s", entry.cacheNamespace, key)
  68. }
  69. func (entry *CacheStoreRedisEntry) FullKey(key string) string {
  70. return fmt.Sprintf("%s:%s", entry.cacheNamespace, key)
  71. }
  72. func (entry *CacheStoreRedisEntry) pureKey(key string) string {
  73. return key[len(entry.cacheNamespace):]
  74. }
  75. func (entry *CacheStoreRedisEntry) Namespace() string {
  76. return entry.cacheNamespace
  77. }
  78. func (entry *CacheStoreRedisEntry) SetNamespace(ns string) {
  79. entry.cacheNamespace = ns
  80. }
  81. func (entry *CacheStoreRedisEntry) Client() *redisv7.Client {
  82. return entry.client
  83. }
  84. func (entry *CacheStoreRedisEntry) BatchGet(ctx context.Context, objects []CacheObject) (map[string]interface{}, error) {
  85. result := make(map[string]interface{})
  86. for _, obj := range objects {
  87. got, err := entry.Get(ctx, obj)
  88. if err != nil {
  89. return nil, xerr.WithMessage(err, obj.CacheKey())
  90. }
  91. if got != nil {
  92. result[obj.CacheKey()] = got
  93. }
  94. }
  95. return result, nil
  96. }
  97. func (entry *CacheStoreRedisEntry) Get(ctx context.Context, obj CacheObject) (interface{}, error) {
  98. got, err := entry.cacheMarshal.Get(entry.fullKey(obj.CacheKey()), obj)
  99. if err != nil {
  100. if err == redisv7.Nil {
  101. return nil, nil
  102. }
  103. return nil, xerr.WithStack(err)
  104. }
  105. return got, nil
  106. }
  107. func (entry *CacheStoreRedisEntry) Set(ctx context.Context, obj CacheObject, options *store.Options) error {
  108. return entry.cacheMarshal.Set(entry.fullKey(obj.CacheKey()), obj, options)
  109. }
  110. func (entry *CacheStoreRedisEntry) TTL(ctx context.Context, obj CacheObject) (time.Duration, error) {
  111. return entry.client.TTL(entry.fullKey(obj.CacheKey())).Result()
  112. }
  113. func (entry *CacheStoreRedisEntry) Delete(ctx context.Context, keys ...interface{}) error {
  114. for _, key := range keys {
  115. switch keyItem := key.(type) {
  116. case string:
  117. if err := entry.cacheMarshal.Delete(entry.fullKey(keyItem)); err != nil {
  118. return xerr.WithStack(err)
  119. }
  120. case CacheObject:
  121. if err := entry.cacheMarshal.Delete(entry.fullKey(keyItem.CacheKey())); err != nil {
  122. return xerr.WithStack(err)
  123. }
  124. default:
  125. return xerr.New("invalid redis key type")
  126. }
  127. }
  128. return nil
  129. }