@@ -3,6 +3,8 @@ package redis
33import (
44 "context"
55 "fmt"
6+ "os"
7+ "sync"
68 "time"
79
810 "github.com/go-redis/redis/v8"
@@ -13,29 +15,50 @@ var redisClient *redis.Client
1315var redisAddr string
1416var redisPassword string
1517var redisDB int
18+ var clientMutex sync.RWMutex
1619
1720type RedisClient struct {
1821 client * redis.Client
1922}
2023
2124func InitRedis (addr string , password string , db int ) error {
25+ clientMutex .Lock ()
26+ defer clientMutex .Unlock ()
27+
2228 redisAddr = addr
2329 redisPassword = password
2430 redisDB = db
2531
2632 // Don't use sync.Once with prefork mode - each process needs its own connection
2733 redisClient = redis .NewClient (& redis.Options {
28- Addr : addr ,
29- Password : password ,
30- DB : db ,
34+ Addr : addr ,
35+ Password : password ,
36+ DB : db ,
37+ PoolSize : 10 ,
38+ MinIdleConns : 5 ,
39+ MaxRetries : 3 ,
40+ PoolTimeout : time .Second * 4 ,
41+ IdleTimeout : time .Minute * 5 ,
42+ DialTimeout : time .Second * 5 ,
43+ ReadTimeout : time .Second * 3 ,
44+ WriteTimeout : time .Second * 3 ,
45+ PoolFIFO : false ,
3146 })
3247
33- _ , err := redisClient .Ping (ctx ).Result ()
48+ ctxTimeout , cancel := context .WithTimeout (ctx , time .Second * 5 )
49+ defer cancel ()
50+
51+ _ , err := redisClient .Ping (ctxTimeout ).Result ()
3452 if err != nil {
53+ redisClient .Close ()
54+ redisClient = nil
3555 return fmt .Errorf ("could not connect to Redis: %v" , err )
3656 }
3757
38- // fmt.Print("Redis connected successfully\n")
58+ if os .Getenv ("FIBER_PREFORK_CHILD" ) == "" {
59+ fmt .Print ("Redis connected successfully\n " )
60+ }
61+
3962 return nil
4063}
4164
@@ -49,18 +72,29 @@ func (r *RedisClient) Set(key string, value interface{}, expirationSeconds int)
4972}
5073
5174func Get (key string ) (string , error ) {
52- if redisClient == nil {
53- if redisAddr != "" {
54- err := InitRedis (redisAddr , redisPassword , redisDB )
55- if err != nil {
56- return "" , fmt .Errorf ("redis client not initialized and re-initialization failed: %v" , err )
75+ clientMutex .RLock ()
76+ client := redisClient
77+ clientMutex .RUnlock ()
78+
79+ if client == nil {
80+ clientMutex .Lock ()
81+ if redisClient == nil {
82+ if redisAddr != "" {
83+ err := InitRedis (redisAddr , redisPassword , redisDB )
84+ if err != nil {
85+ clientMutex .Unlock ()
86+ return "" , fmt .Errorf ("redis client not initialized and re-initialization failed: %v" , err )
87+ }
88+ } else {
89+ clientMutex .Unlock ()
90+ return "" , fmt .Errorf ("redis client not initialized. Call InitRedis() first" )
5791 }
58- } else {
59- return "" , fmt .Errorf ("redis client not initialized. Call InitRedis() first" )
6092 }
93+ client = redisClient
94+ clientMutex .Unlock ()
6195 }
6296
63- val , err := redisClient .Get (ctx , key ).Result ()
97+ val , err := client .Get (ctx , key ).Result ()
6498 if err != nil {
6599 if err == redis .Nil {
66100 return "" , nil
@@ -72,12 +106,24 @@ func Get(key string) (string, error) {
72106
73107func NewRedisClient (addr string , password string , db int ) * RedisClient {
74108 rdb := redis .NewClient (& redis.Options {
75- Addr : addr ,
76- Password : password ,
77- DB : db ,
109+ Addr : addr ,
110+ Password : password ,
111+ DB : db ,
112+ PoolSize : 10 ,
113+ MinIdleConns : 5 ,
114+ MaxRetries : 3 ,
115+ PoolTimeout : time .Second * 4 ,
116+ IdleTimeout : time .Minute * 5 ,
117+ DialTimeout : time .Second * 5 ,
118+ ReadTimeout : time .Second * 3 ,
119+ WriteTimeout : time .Second * 3 ,
120+ PoolFIFO : false ,
78121 })
79122
80- _ , err := rdb .Ping (ctx ).Result ()
123+ ctxTimeout , cancel := context .WithTimeout (ctx , time .Second * 5 )
124+ defer cancel ()
125+
126+ _ , err := rdb .Ping (ctxTimeout ).Result ()
81127 if err != nil {
82128 panic (fmt .Errorf ("could not connect to Redis: %v" , err ))
83129 }
@@ -86,19 +132,30 @@ func NewRedisClient(addr string, password string, db int) *RedisClient {
86132}
87133
88134func Set (key string , value interface {}, expirationSeconds int ) error {
89- if redisClient == nil {
90- if redisAddr != "" {
91- err := InitRedis (redisAddr , redisPassword , redisDB )
92- if err != nil {
93- return fmt .Errorf ("redis client not initialized and re-initialization failed: %v" , err )
135+ clientMutex .RLock ()
136+ client := redisClient
137+ clientMutex .RUnlock ()
138+
139+ if client == nil {
140+ clientMutex .Lock ()
141+ if redisClient == nil {
142+ if redisAddr != "" {
143+ err := InitRedis (redisAddr , redisPassword , redisDB )
144+ if err != nil {
145+ clientMutex .Unlock ()
146+ return fmt .Errorf ("redis client not initialized and re-initialization failed: %v" , err )
147+ }
148+ } else {
149+ clientMutex .Unlock ()
150+ return fmt .Errorf ("redis client not initialized. Call InitRedis() first" )
94151 }
95- } else {
96- return fmt .Errorf ("redis client not initialized. Call InitRedis() first" )
97152 }
153+ client = redisClient
154+ clientMutex .Unlock ()
98155 }
99156
100157 expiration := time .Duration (expirationSeconds ) * time .Second
101- err := redisClient .Set (ctx , key , value , expiration ).Err ()
158+ err := client .Set (ctx , key , value , expiration ).Err ()
102159 if err != nil {
103160 return fmt .Errorf ("could not set value in Redis: %v" , err )
104161 }
0 commit comments