| | package xcache
|
| |
|
| | import (
|
| | "context"
|
| | "errors"
|
| | "fmt"
|
| | "time"
|
| |
|
| | "github.com/eko/gocache/lib/v4/store"
|
| |
|
| | cachelib "github.com/eko/gocache/lib/v4/cache"
|
| | gocache_store "github.com/eko/gocache/store/go_cache/v4"
|
| | gocache "github.com/patrickmn/go-cache"
|
| | redis "github.com/redis/go-redis/v9"
|
| |
|
| | "github.com/looplj/axonhub/internal/log"
|
| | redis_store "github.com/looplj/axonhub/internal/pkg/xcache/redis"
|
| | "github.com/looplj/axonhub/internal/pkg/xredis"
|
| | )
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | type Cache[T any] = cachelib.CacheInterface[T]
|
| |
|
| | type SetterCache[T any] = cachelib.SetterCacheInterface[T]
|
| |
|
| |
|
| |
|
| |
|
| | func NewMemory[T any](client *gocache.Cache, options ...Option) SetterCache[T] {
|
| | store := gocache_store.NewGoCache(client, options...)
|
| | return cachelib.New[T](store)
|
| | }
|
| |
|
| |
|
| |
|
| | func NewMemoryWithOptions[T any](defaultExpiration, cleanupInterval time.Duration, options ...Option) SetterCache[T] {
|
| | client := gocache.New(defaultExpiration, cleanupInterval)
|
| | return NewMemory[T](client, options...)
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | func NewFromConfig[T any](cfg Config) Cache[T] {
|
| |
|
| | if cfg.Mode == "" {
|
| | return NewNoop[T]()
|
| | }
|
| |
|
| |
|
| | memExpiration := defaultIfZero(cfg.Memory.Expiration, 5*time.Minute)
|
| | memCleanupInterval := defaultIfZero(cfg.Memory.CleanupInterval, 10*time.Minute)
|
| |
|
| | memClient := gocache.New(memExpiration, memCleanupInterval)
|
| | memStore := gocache_store.NewGoCache(memClient, store.WithExpiration(memExpiration))
|
| | mem := cachelib.New[T](memStore)
|
| |
|
| |
|
| | var rds SetterCache[T]
|
| |
|
| | if (cfg.Redis.Addr != "" || cfg.Redis.URL != "") && cfg.Mode != ModeMemory {
|
| | client, err := xredis.NewClient(cfg.Redis)
|
| | if err != nil {
|
| | panic(fmt.Errorf("invalid redis config: %w", err))
|
| | }
|
| |
|
| | redisExpiration := defaultIfZero(cfg.Redis.Expiration, 30*time.Minute)
|
| | rdsStore := redis_store.NewRedisStore[T](client, store.WithExpiration(redisExpiration))
|
| | rds = cachelib.New[T](rdsStore)
|
| | }
|
| |
|
| | switch cfg.Mode {
|
| | case ModeTwoLevel:
|
| | if rds != nil {
|
| | log.Info(context.Background(), "Using two-level cache")
|
| | return cachelib.NewChain[T](mem, rds)
|
| | }
|
| |
|
| | return mem
|
| | case ModeRedis:
|
| | if rds == nil {
|
| | panic(errors.New("redis cache config is invalid"))
|
| | }
|
| |
|
| | log.Info(context.Background(), "Using redis cache")
|
| |
|
| | return rds
|
| | case ModeMemory:
|
| | log.Info(context.Background(), "Using memory cache")
|
| | return mem
|
| | default:
|
| | log.Info(context.Background(), "Disable cache")
|
| |
|
| | return NewNoop[T]()
|
| | }
|
| | }
|
| |
|
| | func defaultIfZero(d, def time.Duration) time.Duration {
|
| | if d == 0 {
|
| | return def
|
| | }
|
| |
|
| | return d
|
| | }
|
| |
|
| |
|
| |
|
| | func NewRedis[T any](client *redis.Client, options ...Option) SetterCache[T] {
|
| | store := redis_store.NewRedisStore[T](client, options...)
|
| | return cachelib.New[T](store)
|
| | }
|
| |
|
| |
|
| | func NewRedisWithOptions[T any](opts *redis.Options, options ...Option) SetterCache[T] {
|
| | client := redis.NewClient(opts)
|
| | return NewRedis[T](client, options...)
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | func NewTwoLevel[T any](memory SetterCache[T], redis SetterCache[T]) Cache[T] {
|
| | return cachelib.NewChain[T](memory, redis)
|
| | }
|
| |
|
| |
|
| | func NewTwoLevelWithClients[T any](memClient *gocache.Cache, redisClient *redis.Client, memOptions []Option, redisOptions []Option) Cache[T] {
|
| | mem := NewMemory[T](memClient, memOptions...)
|
| | rds := NewRedis[T](redisClient, redisOptions...)
|
| |
|
| | return NewTwoLevel[T](mem, rds)
|
| | }
|
| |
|