package cache import ( "context" "fmt" "time" "github.com/dgraph-io/ristretto" "github.com/eko/gocache/lib/v4/cache" "github.com/eko/gocache/lib/v4/store" redis_store "github.com/eko/gocache/store/redis/v4" ristretto_store "github.com/eko/gocache/store/ristretto/v4" "github.com/redis/go-redis/v9" "github.com/rs/zerolog/log" "gitlab.com/mstarongitlab/linstrom/config" ) type Cache struct { cache *cache.ChainCache[[]byte] decoders *DecoderPool encoders *EncoderPool } var ctxBackground = context.Background() // TODO: Maybe also include metrics func NewCache(maxSize int64, redisUrl *string) (*Cache, error) { // ristretto is an in-memory cache log.Debug().Int64("max-size", maxSize).Msg("Setting up ristretto") ristrettoCache, err := ristretto.NewCache(&ristretto.Config{ // The *10 is a recommendation from ristretto NumCounters: maxSize * 10, MaxCost: maxSize, BufferItems: 64, // Same here }) if err != nil { return nil, fmt.Errorf("ristretto cache error: %w", err) } ristrettoStore := ristretto_store.NewRistretto( ristrettoCache, store.WithExpiration( time.Second*time.Duration(config.GlobalConfig.Storage.MaxInMemoryCacheSize), ), ) var cacheManager *cache.ChainCache[[]byte] if redisUrl != nil { opts, err := redis.ParseURL(*redisUrl) if err != nil { return nil, err } redisClient := redis.NewClient(opts) redisStore := redis_store.NewRedis( redisClient, store.WithExpiration( time.Second*time.Duration(*config.GlobalConfig.Storage.MaxRedisCacheTTL), ), ) cacheManager = cache.NewChain( cache.New[[]byte](ristrettoStore), cache.New[[]byte](redisStore), ) } else { cacheManager = cache.NewChain(cache.New[[]byte](ristrettoStore)) } return &Cache{ cache: cacheManager, decoders: NewDecoderPool(), encoders: NewEncoderPool(), }, nil } func (c *Cache) Get(key string, target any) (bool, error) { data, err := c.cache.Get(ctxBackground, key) if err != nil { return false, err } err = c.decoders.Decode(data, target) if err != nil { return false, err } return true, err } func (c *Cache) Set(key string, value any) error { data, err := c.encoders.Encode(value) if err != nil { return err } err = c.cache.Set(ctxBackground, key, data, nil) return err } func (c *Cache) Delete(key string) { // Error return doesn't matter here. Delete is delete is gone _ = c.cache.Delete(ctxBackground, key) }