chat_back_go/internal/service/cache.go

72 lines
1.7 KiB
Go

package service
import (
"context"
"encoding"
"errors"
"github.com/redis/go-redis/v9"
"sync"
"time"
"git.urec56.ru/urec/chat_back_go/internal/domain"
"git.urec56.ru/urec/chat_back_go/internal/logger"
)
type cacheService struct {
l *logger.Logger
r redis.UniversalClient
storage *sync.Map
}
type userCache struct {
u []byte // domain.User
expiresAt time.Time
}
func newCacheService(r redis.UniversalClient, l *logger.Logger) *cacheService {
return &cacheService{r: r, l: l, storage: &sync.Map{}}
}
func (c *cacheService) Get(key string, v encoding.BinaryUnmarshaler, isFast bool) error {
return c.GetCtx(context.Background(), key, v, isFast)
}
func (c *cacheService) GetCtx(ctx context.Context, key string, v encoding.BinaryUnmarshaler, isFast bool) error {
if isFast {
item, ok := c.storage.Load(key)
if ok {
if userData, ok := item.(userCache); ok && userData.expiresAt.After(time.Now()) {
err := v.UnmarshalBinary(userData.u)
return err
}
}
}
err := c.r.Get(ctx, key).Scan(v)
if err != nil {
if errors.Is(err, redis.Nil) {
return domain.NoKeyFoundError
}
c.l.Errorf("getting key %s: %s", key, err)
return domain.InternalServerError
}
return nil
}
func (c *cacheService) Set(key string, v encoding.BinaryMarshaler, ex time.Duration) error {
return c.SetCtx(context.Background(), key, v, ex)
}
func (c *cacheService) SetCtx(ctx context.Context, key string, v encoding.BinaryMarshaler, ex time.Duration) error {
if err := c.r.SetEx(ctx, key, v, ex).Err(); err != nil {
return err
}
data, err := v.MarshalBinary()
if err != nil {
return err
}
c.storage.Store(key, userCache{u: data, expiresAt: time.Now().Add(time.Minute)})
return nil
}