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