package services import ( "context" "errors" "fmt" "log" "time" "github.com/redis/go-redis/v9" ) var CacheClient Cache var ErrCacheMiss = errors.New("cache: miss") type Cache interface { Get(ctx context.Context, key string) ([]byte, error) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error } type RedisConcrete struct { Redis *redis.Client } const cacheOperationTimeout = 100 * time.Millisecond func (svc RedisConcrete) Get(ctx context.Context, key string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, cacheOperationTimeout) defer cancel() value, err := svc.Redis.Get(ctx, key).Bytes() if errors.Is(err, redis.Nil) { return nil, ErrCacheMiss } if err != nil { return nil, err } return value, nil } func (svc RedisConcrete) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error { ctx, cancel := context.WithTimeout(ctx, cacheOperationTimeout) defer cancel() return svc.Redis.Set(ctx, key, value, ttl).Err() } func (svc RedisConcrete) Close() error { return svc.Redis.Close() } func (svc RedisConcrete) AssertSuccessfulConnection(ctx context.Context) { if err := svc.Redis.Ping(ctx).Err(); err != nil { log.Printf("WARNING: %s", fmt.Errorf("redis: cannot reach cache at %q, searches will be served from the database: %w", svc.Redis.Options().Addr, err)) } }