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  }