89 lines
1.9 KiB
Go
89 lines
1.9 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.intra.yksa.space/gsn/predictor/internal/pkg/errcodes"
|
|
"github.com/bsm/redislock"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
type Client struct {
|
|
client *redis.Client
|
|
locker *redislock.Client
|
|
}
|
|
|
|
// Ensure Client implements Service interface
|
|
var _ Service = (*Client)(nil)
|
|
|
|
type Config struct {
|
|
Host string
|
|
Port int
|
|
Password string
|
|
DB int
|
|
}
|
|
|
|
func New(cfg Config) (*Client, error) {
|
|
client := redis.NewClient(&redis.Options{
|
|
Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
|
|
Password: cfg.Password,
|
|
DB: cfg.DB,
|
|
})
|
|
|
|
// Test connection
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
if err := client.Ping(ctx).Err(); err != nil {
|
|
return nil, fmt.Errorf("failed to connect to redis: %w", err)
|
|
}
|
|
|
|
locker := redislock.New(client)
|
|
|
|
return &Client{
|
|
client: client,
|
|
locker: locker,
|
|
}, nil
|
|
}
|
|
|
|
func (c *Client) Lock(ctx context.Context, key string, ttl time.Duration) (func(context.Context), error) {
|
|
lock, err := c.locker.Obtain(ctx, key, ttl, nil)
|
|
if err != nil {
|
|
if err == redislock.ErrNotObtained {
|
|
return nil, errcodes.ErrRedisLockAlreadyLocked
|
|
}
|
|
return nil, errcodes.Wrap(err, "failed to obtain redis lock")
|
|
}
|
|
|
|
unlock := func(ctx context.Context) {
|
|
lock.Release(ctx)
|
|
}
|
|
|
|
return unlock, nil
|
|
}
|
|
|
|
func (c *Client) Set(key string, value []byte, ttl time.Duration) error {
|
|
ctx := context.Background()
|
|
if err := c.client.Set(ctx, key, value, ttl).Err(); err != nil {
|
|
return errcodes.Wrap(err, "failed to set redis key")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Get(key string) ([]byte, error) {
|
|
ctx := context.Background()
|
|
result := c.client.Get(ctx, key)
|
|
if result.Err() != nil {
|
|
if result.Err() == redis.Nil {
|
|
return nil, errcodes.ErrRedisCacheMiss
|
|
}
|
|
return nil, errcodes.Wrap(result.Err(), "failed to get redis key")
|
|
}
|
|
return result.Bytes()
|
|
}
|
|
|
|
func (c *Client) Close() error {
|
|
return c.client.Close()
|
|
}
|