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

// 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
}