You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.4 KiB
Go
166 lines
4.4 KiB
Go
// Package redis provides Redis client for the KnowFoolery application.
|
|
package redis
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
redisv9 "github.com/redis/go-redis/v9"
|
|
|
|
"knowfoolery/backend/shared/infra/utils/envutil"
|
|
)
|
|
|
|
// Config holds the configuration for the Redis client.
|
|
type Config struct {
|
|
Host string
|
|
Port int
|
|
Password string
|
|
DB int
|
|
PoolSize int
|
|
MinIdleConns int
|
|
DialTimeout time.Duration
|
|
ReadTimeout time.Duration
|
|
WriteTimeout time.Duration
|
|
}
|
|
|
|
// DefaultConfig returns a default configuration for development.
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
Host: "localhost",
|
|
Port: 6379,
|
|
Password: "",
|
|
DB: 0,
|
|
PoolSize: 10,
|
|
MinIdleConns: 5,
|
|
DialTimeout: 5 * time.Second,
|
|
ReadTimeout: 3 * time.Second,
|
|
WriteTimeout: 3 * time.Second,
|
|
}
|
|
}
|
|
|
|
// Addr returns the Redis server address.
|
|
func (c Config) Addr() string {
|
|
return fmt.Sprintf("%s:%d", c.Host, c.Port)
|
|
}
|
|
|
|
// Client wraps Redis operations.
|
|
// This is a placeholder that should be replaced with an actual Redis client.
|
|
type Client struct {
|
|
config Config
|
|
client *redisv9.Client
|
|
}
|
|
|
|
// NewClient creates a new Redis client.
|
|
func NewClient(config Config) (*Client, error) {
|
|
if err := validateConfig(config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client := redisv9.NewClient(&redisv9.Options{
|
|
Addr: config.Addr(),
|
|
Password: config.Password,
|
|
DB: config.DB,
|
|
PoolSize: config.PoolSize,
|
|
MinIdleConns: config.MinIdleConns,
|
|
DialTimeout: config.DialTimeout,
|
|
ReadTimeout: config.ReadTimeout,
|
|
WriteTimeout: config.WriteTimeout,
|
|
})
|
|
|
|
return &Client{
|
|
config: config,
|
|
client: client,
|
|
}, nil
|
|
}
|
|
|
|
// Close closes the Redis connection.
|
|
func (c *Client) Close() error {
|
|
return c.client.Close()
|
|
}
|
|
|
|
// Ping checks if the Redis connection is alive.
|
|
func (c *Client) Ping(ctx context.Context) error {
|
|
return c.client.Ping(ctx).Err()
|
|
}
|
|
|
|
// HealthCheck performs a health check on Redis.
|
|
func (c *Client) HealthCheck(ctx context.Context) error {
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
|
|
return c.Ping(ctx)
|
|
}
|
|
|
|
// Set stores a key-value pair with expiration.
|
|
func (c *Client) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
|
|
return c.client.Set(ctx, key, value, expiration).Err()
|
|
}
|
|
|
|
// Get retrieves a value by key.
|
|
func (c *Client) Get(ctx context.Context, key string) (string, error) {
|
|
return c.client.Get(ctx, key).Result()
|
|
}
|
|
|
|
// Delete removes a key.
|
|
func (c *Client) Delete(ctx context.Context, keys ...string) error {
|
|
return c.client.Del(ctx, keys...).Err()
|
|
}
|
|
|
|
// Exists checks if a key exists.
|
|
func (c *Client) Exists(ctx context.Context, key string) (bool, error) {
|
|
n, err := c.client.Exists(ctx, key).Result()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return n > 0, nil
|
|
}
|
|
|
|
// Incr increments a counter.
|
|
func (c *Client) Incr(ctx context.Context, key string) (int64, error) {
|
|
return c.client.Incr(ctx, key).Result()
|
|
}
|
|
|
|
// Expire sets expiration on a key.
|
|
func (c *Client) Expire(ctx context.Context, key string, expiration time.Duration) error {
|
|
return c.client.Expire(ctx, key, expiration).Err()
|
|
}
|
|
|
|
// ConfigFromEnv creates a Config from environment variables.
|
|
func ConfigFromEnv() Config {
|
|
cfg := DefaultConfig()
|
|
|
|
cfg.Host = envutil.String("REDIS_HOST", cfg.Host)
|
|
cfg.Port = envutil.Int("REDIS_PORT", cfg.Port)
|
|
cfg.Password = envutil.String("REDIS_PASSWORD", cfg.Password)
|
|
cfg.DB = envutil.Int("REDIS_DB", cfg.DB)
|
|
cfg.PoolSize = envutil.Int("REDIS_POOL_SIZE", cfg.PoolSize)
|
|
cfg.MinIdleConns = envutil.Int("REDIS_MIN_IDLE_CONNS", cfg.MinIdleConns)
|
|
cfg.DialTimeout = envutil.Duration("REDIS_DIAL_TIMEOUT", cfg.DialTimeout)
|
|
cfg.ReadTimeout = envutil.Duration("REDIS_READ_TIMEOUT", cfg.ReadTimeout)
|
|
cfg.WriteTimeout = envutil.Duration("REDIS_WRITE_TIMEOUT", cfg.WriteTimeout)
|
|
|
|
return cfg
|
|
}
|
|
|
|
func validateConfig(c Config) error {
|
|
switch {
|
|
case c.Host == "":
|
|
return errors.New("redis host is required")
|
|
case c.Port <= 0:
|
|
return errors.New("redis port must be greater than 0")
|
|
case c.PoolSize <= 0:
|
|
return errors.New("redis pool size must be greater than 0")
|
|
case c.MinIdleConns < 0:
|
|
return errors.New("redis min idle conns must be >= 0")
|
|
case c.DialTimeout <= 0:
|
|
return errors.New("redis dial timeout must be greater than 0")
|
|
case c.ReadTimeout <= 0:
|
|
return errors.New("redis read timeout must be greater than 0")
|
|
case c.WriteTimeout <= 0:
|
|
return errors.New("redis write timeout must be greater than 0")
|
|
}
|
|
return nil
|
|
}
|