github.com/zhongdalu/gf@v1.0.0/g/database/gredis/gredis.go (about) 1 // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // Package gredis provides convenient client for redis server. 8 // 9 // Redis Client. 10 // 11 // Redis Commands Official: https://redis.io/commands 12 // 13 // Redis Chinese Documentation: http://redisdoc.com/ 14 package gredis 15 16 import ( 17 "fmt" 18 "github.com/zhongdalu/gf/g/container/gmap" 19 "github.com/zhongdalu/gf/g/container/gvar" 20 "github.com/zhongdalu/gf/third/github.com/gomodule/redigo/redis" 21 "time" 22 ) 23 24 const ( 25 gDEFAULT_POOL_IDLE_TIMEOUT = 60 * time.Second 26 gDEFAULT_POOL_MAX_LIFE_TIME = 60 * time.Second 27 ) 28 29 // Redis client. 30 type Redis struct { 31 pool *redis.Pool // Underlying connection pool. 32 group string // Configuration group. 33 config Config // Configuration. 34 } 35 36 // Redis connection. 37 type Conn struct { 38 redis.Conn 39 } 40 41 // Redis configuration. 42 type Config struct { 43 Host string 44 Port int 45 Db int 46 Pass string // Password for AUTH. 47 MaxIdle int // Maximum number of connections allowed to be idle (default is 0 means no idle connection) 48 MaxActive int // Maximum number of connections limit (default is 0 means no limit) 49 IdleTimeout time.Duration // Maximum idle time for connection (default is 60 seconds, not allowed to be set to 0) 50 MaxConnLifetime time.Duration // Maximum lifetime of the connection (default is 60 seconds, not allowed to be set to 0) 51 } 52 53 // Pool statistics. 54 type PoolStats struct { 55 redis.PoolStats 56 } 57 58 var ( 59 // Instance map 60 instances = gmap.NewStrAnyMap() 61 // Pool map. 62 pools = gmap.NewStrAnyMap() 63 ) 64 65 // New creates a redis client object with given configuration. 66 // Redis client maintains a connection pool automatically. 67 func New(config Config) *Redis { 68 if config.IdleTimeout == 0 { 69 config.IdleTimeout = gDEFAULT_POOL_IDLE_TIMEOUT 70 } 71 if config.MaxConnLifetime == 0 { 72 config.MaxConnLifetime = gDEFAULT_POOL_MAX_LIFE_TIME 73 } 74 return &Redis{ 75 config: config, 76 pool: pools.GetOrSetFuncLock(fmt.Sprintf("%v", config), func() interface{} { 77 return &redis.Pool{ 78 IdleTimeout: config.IdleTimeout, 79 MaxConnLifetime: config.MaxConnLifetime, 80 Dial: func() (redis.Conn, error) { 81 c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port)) 82 if err != nil { 83 return nil, err 84 } 85 // AUTH 86 if len(config.Pass) > 0 { 87 if _, err := c.Do("AUTH", config.Pass); err != nil { 88 return nil, err 89 } 90 } 91 // DB 92 if _, err := c.Do("SELECT", config.Db); err != nil { 93 return nil, err 94 } 95 return c, nil 96 }, 97 // After the conn is taken from the connection pool, to test if the connection is available, 98 // If error is returned then it closes the connection object and recreate a new connection. 99 TestOnBorrow: func(c redis.Conn, t time.Time) error { 100 _, err := c.Do("PING") 101 return err 102 }, 103 } 104 }).(*redis.Pool), 105 } 106 } 107 108 // Instance returns an instance of redis client with specified group. 109 // The <group> param is unnecessary, if <group> is not passed, 110 // it returns a redis instance with default group. 111 func Instance(name ...string) *Redis { 112 group := DEFAULT_GROUP_NAME 113 if len(name) > 0 { 114 group = name[0] 115 } 116 v := instances.GetOrSetFuncLock(group, func() interface{} { 117 if config, ok := GetConfig(group); ok { 118 r := New(config) 119 r.group = group 120 return r 121 } 122 return nil 123 }) 124 if v != nil { 125 return v.(*Redis) 126 } 127 return nil 128 } 129 130 // Close closes the redis connection pool, 131 // it will release all connections reserved by this pool. 132 // It is not necessary to call Close manually. 133 func (r *Redis) Close() error { 134 if r.group != "" { 135 // If it is an instance object, it needs to remove it from the instance Map. 136 instances.Remove(r.group) 137 } 138 pools.Remove(fmt.Sprintf("%v", r.config)) 139 return r.pool.Close() 140 } 141 142 // Conn returns a raw underlying connection object, 143 // which expose more methods to communicate with server. 144 // **You should call Close function manually if you do not use this connection any further.** 145 func (r *Redis) Conn() *Conn { 146 return &Conn{r.pool.Get()} 147 } 148 149 // Alias of Conn, see Conn. 150 func (r *Redis) GetConn() *Conn { 151 return r.Conn() 152 } 153 154 // SetMaxIdle sets the MaxIdle attribute of the connection pool. 155 func (r *Redis) SetMaxIdle(value int) { 156 r.pool.MaxIdle = value 157 } 158 159 // SetMaxActive sets the MaxActive attribute of the connection pool. 160 func (r *Redis) SetMaxActive(value int) { 161 r.pool.MaxActive = value 162 } 163 164 // SetIdleTimeout sets the IdleTimeout attribute of the connection pool. 165 func (r *Redis) SetIdleTimeout(value time.Duration) { 166 r.pool.IdleTimeout = value 167 } 168 169 // SetMaxConnLifetime sets the MaxConnLifetime attribute of the connection pool. 170 func (r *Redis) SetMaxConnLifetime(value time.Duration) { 171 r.pool.MaxConnLifetime = value 172 } 173 174 // Stats returns pool's statistics. 175 func (r *Redis) Stats() *PoolStats { 176 return &PoolStats{r.pool.Stats()} 177 } 178 179 // Do sends a command to the server and returns the received reply. 180 // Do automatically get a connection from pool, and close it when reply received. 181 // It does not really "close" the connection, but drop it back to the connection pool. 182 func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) { 183 conn := &Conn{r.pool.Get()} 184 defer conn.Close() 185 return conn.Do(command, args...) 186 } 187 188 // DoVar returns value from Do as gvar.Var. 189 func (r *Redis) DoVar(command string, args ...interface{}) (*gvar.Var, error) { 190 v, err := r.Do(command, args...) 191 return gvar.New(v, true), err 192 } 193 194 // Deprecated. 195 // Send writes the command to the client's output buffer. 196 func (r *Redis) Send(command string, args ...interface{}) error { 197 conn := &Conn{r.pool.Get()} 198 defer conn.Close() 199 return conn.Send(command, args...) 200 }