gf/database/gredis/gredis.go

196 lines
5.7 KiB
Go
Raw Normal View History

// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2018-04-18 18:05:46 +08:00
//
// 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.
2018-04-18 18:05:46 +08:00
// Package gredis provides convenient client for redis server.
2019-01-16 13:35:16 +08:00
//
2019-05-08 21:03:04 +08:00
// Redis Client.
2019-05-14 22:02:09 +08:00
//
2019-05-08 21:03:04 +08:00
// Redis Commands Official: https://redis.io/commands
2019-05-14 22:02:09 +08:00
//
2019-05-08 21:03:04 +08:00
// Redis Chinese Documentation: http://redisdoc.com/
2018-04-18 18:05:46 +08:00
package gredis
import (
2019-06-19 09:06:52 +08:00
"fmt"
2019-12-04 18:43:16 +08:00
"github.com/gogf/gf/util/gconv"
2019-06-19 09:06:52 +08:00
"time"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/container/gvar"
"github.com/gomodule/redigo/redis"
2018-04-18 18:05:46 +08:00
)
2019-05-08 21:03:04 +08:00
// Redis client.
2018-04-18 18:05:46 +08:00
type Redis struct {
2019-06-19 09:06:52 +08:00
pool *redis.Pool // Underlying connection pool.
group string // Configuration group.
config Config // Configuration.
2018-04-18 18:05:46 +08:00
}
2019-05-08 21:03:04 +08:00
// Redis connection.
type Conn struct {
redis.Conn
}
2019-05-08 21:03:04 +08:00
// Redis configuration.
2018-06-05 21:18:41 +08:00
type Config struct {
2019-06-19 09:06:52 +08:00
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)
ConnectTimeout time.Duration // Dial connection timeout.
2018-06-05 21:18:41 +08:00
}
2019-05-08 21:03:04 +08:00
// Pool statistics.
2018-04-18 18:05:46 +08:00
type PoolStats struct {
2019-06-19 09:06:52 +08:00
redis.PoolStats
2018-04-18 18:05:46 +08:00
}
const (
2020-03-08 00:17:42 +08:00
gDEFAULT_POOL_IDLE_TIMEOUT = 30 * time.Second
gDEFAULT_POOL_CONN_TIMEOUT = 10 * time.Second
2020-03-08 00:17:42 +08:00
gDEFAULT_POOL_MAX_LIFE_TIME = 30 * time.Second
)
var (
2019-06-19 09:06:52 +08:00
// Pool map.
pools = gmap.NewStrAnyMap(true)
)
// New creates a redis client object with given configuration.
// Redis client maintains a connection pool automatically.
2018-06-05 21:18:41 +08:00
func New(config Config) *Redis {
2019-06-19 09:06:52 +08:00
if config.IdleTimeout == 0 {
config.IdleTimeout = gDEFAULT_POOL_IDLE_TIMEOUT
}
if config.ConnectTimeout == 0 {
config.ConnectTimeout = gDEFAULT_POOL_CONN_TIMEOUT
}
2019-06-19 09:06:52 +08:00
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{
2020-03-08 00:17:42 +08:00
Wait: true,
2019-06-19 09:06:52 +08:00
IdleTimeout: config.IdleTimeout,
MaxActive: config.MaxActive,
MaxIdle: config.MaxIdle,
2019-06-19 09:06:52 +08:00
MaxConnLifetime: config.MaxConnLifetime,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial(
"tcp",
fmt.Sprintf("%s:%d", config.Host, config.Port),
redis.DialConnectTimeout(config.ConnectTimeout),
)
2019-06-19 09:06:52 +08:00
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),
}
2018-04-18 18:05:46 +08:00
}
// 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.
2019-05-08 21:03:04 +08:00
// It is not necessary to call Close manually.
2018-04-18 18:05:46 +08:00
func (r *Redis) Close() error {
2019-06-19 09:06:52 +08:00
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()
2018-04-18 18:05:46 +08:00
}
// Conn returns a raw underlying connection object,
2019-05-08 21:03:04 +08:00
// which expose more methods to communicate with server.
2019-03-21 10:04:53 +08:00
// **You should call Close function manually if you do not use this connection any further.**
func (r *Redis) Conn() *Conn {
2019-06-19 09:06:52 +08:00
return &Conn{r.pool.Get()}
}
// Alias of Conn, see Conn.
func (r *Redis) GetConn() *Conn {
2019-06-19 09:06:52 +08:00
return r.Conn()
}
// SetMaxIdle sets the MaxIdle attribute of the connection pool.
2018-04-18 18:05:46 +08:00
func (r *Redis) SetMaxIdle(value int) {
2019-06-19 09:06:52 +08:00
r.pool.MaxIdle = value
2018-04-18 18:05:46 +08:00
}
2019-05-08 21:03:04 +08:00
// SetMaxActive sets the MaxActive attribute of the connection pool.
2018-04-18 18:05:46 +08:00
func (r *Redis) SetMaxActive(value int) {
2019-06-19 09:06:52 +08:00
r.pool.MaxActive = value
2018-04-18 18:05:46 +08:00
}
2019-05-08 21:03:04 +08:00
// SetIdleTimeout sets the IdleTimeout attribute of the connection pool.
2018-04-18 18:05:46 +08:00
func (r *Redis) SetIdleTimeout(value time.Duration) {
2019-06-19 09:06:52 +08:00
r.pool.IdleTimeout = value
2018-04-18 18:05:46 +08:00
}
2019-05-08 21:03:04 +08:00
// SetMaxConnLifetime sets the MaxConnLifetime attribute of the connection pool.
2018-04-18 18:05:46 +08:00
func (r *Redis) SetMaxConnLifetime(value time.Duration) {
2019-06-19 09:06:52 +08:00
r.pool.MaxConnLifetime = value
2018-04-18 18:05:46 +08:00
}
// Stats returns pool's statistics.
2018-04-18 18:05:46 +08:00
func (r *Redis) Stats() *PoolStats {
2019-06-19 09:06:52 +08:00
return &PoolStats{r.pool.Stats()}
2018-04-18 18:05:46 +08:00
}
// 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.
2018-04-18 18:05:46 +08:00
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
2019-06-19 09:06:52 +08:00
conn := &Conn{r.pool.Get()}
defer conn.Close()
return conn.Do(command, args...)
2018-04-18 18:05:46 +08:00
}
// 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...)
2019-12-04 18:43:16 +08:00
if result, ok := v.([]byte); ok {
return gvar.New(gconv.UnsafeBytesToStr(result)), err
}
return gvar.New(v), err
}