// Package util provide some utility functions package util import ( "context" "errors" "fmt" "time" "modelRT/config" redigo "github.com/gomodule/redigo/redis" "github.com/redis/go-redis/v9" ) // NewRedisClient define func of initialize the Redis client func NewRedisClient(addr string, opts ...Option) (*redis.Client, error) { // default options configs := &clientConfig{ Options: &redis.Options{ Addr: addr, DialTimeout: 5 * time.Second, ReadTimeout: 3 * time.Second, WriteTimeout: 3 * time.Second, PoolSize: 10, }, } // Apply configuration options from config var errs []error for _, opt := range opts { if err := opt(configs); err != nil { errs = append(errs, err) } } if len(errs) > 0 { return nil, fmt.Errorf("failed to apply options: %w", errors.Join(errs...)) } // create redis client client := redis.NewClient(configs.Options) if configs.DialTimeout > 0 { // check if the connection is successful ctx, cancel := context.WithTimeout(context.Background(), configs.DialTimeout) defer cancel() if err := client.Ping(ctx).Err(); err != nil { return nil, fmt.Errorf("can not connect redis:%v", err) } } return client, nil } // NewRedigoPool define func of initialize the Redigo pool func NewRedigoPool(rCfg config.RedisConfig) (*redigo.Pool, error) { pool := &redigo.Pool{ // TODO optimize IdleTimeout with config parameter MaxIdle: rCfg.PoolSize / 2, MaxActive: rCfg.PoolSize, IdleTimeout: 240 * time.Second, TestOnBorrow: func(c redigo.Conn, t time.Time) error { if time.Since(t) < time.Minute { return nil } _, err := c.Do("PING") return err }, Dial: func() (redigo.Conn, error) { dialTimeout := time.Duration(rCfg.DialTimeout) * time.Second readTimeout := time.Duration(rCfg.ReadTimeout) * time.Second writeTimeout := time.Duration(rCfg.WriteTimeout) * time.Second opts := []redigo.DialOption{ redigo.DialDatabase(rCfg.DB), redigo.DialPassword(rCfg.Password), redigo.DialConnectTimeout(dialTimeout), redigo.DialReadTimeout(readTimeout), redigo.DialWriteTimeout(writeTimeout), } c, err := redigo.Dial("tcp", rCfg.Addr, opts...) if err != nil { return nil, fmt.Errorf("redigo dial failed: %w", err) } return c, nil }, } conn := pool.Get() defer conn.Close() if err := conn.Err(); err != nil { return nil, fmt.Errorf("failed to get connection from pool: %w", err) } _, err := conn.Do("PING") if err != nil { return nil, fmt.Errorf("redis connection test (PING) failed: %w", err) } return pool, nil }