redis_conn.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package redis
  2. import (
  3. "git.aionnect.com/aionnect/go-common/utils"
  4. "git.aionnect.com/aionnect/go-common/utils/logger"
  5. "github.com/gomodule/redigo/redis"
  6. "github.com/mna/redisc"
  7. "github.com/spf13/viper"
  8. "os"
  9. "os/signal"
  10. "strings"
  11. "sync"
  12. "syscall"
  13. "time"
  14. )
  15. type Hub struct {
  16. LOG func() *logger.Logger
  17. pool *redis.Pool
  18. cluster *redisc.Cluster
  19. once sync.Once
  20. }
  21. func NewHub() *Hub {
  22. viper.SetDefault("redis.max_idle", 300)
  23. viper.SetDefault("redis.max_active", 1000)
  24. viper.SetDefault("redis.timeout", time.Duration(60000))
  25. return &Hub{
  26. LOG: func() *logger.Logger {
  27. return logger.New()
  28. },
  29. }
  30. }
  31. func (h *Hub) createPool(addr string, opts ...redis.DialOption) (*redis.Pool, error) {
  32. maxIdle := viper.GetInt("redis.max_idle")
  33. maxActive := viper.GetInt("redis.max_active")
  34. idleTimeout := viper.GetDuration("redis.timeout")
  35. return &redis.Pool{
  36. MaxIdle: maxIdle,
  37. MaxActive: maxActive,
  38. IdleTimeout: idleTimeout,
  39. Dial: func() (redis.Conn, error) {
  40. if conn, err := redis.Dial("tcp", addr, opts...); err != nil {
  41. h.LOG().Warnf("Get Redis connection failed: %s", err.Error())
  42. return nil, err
  43. } else {
  44. return conn, nil
  45. }
  46. },
  47. TestOnBorrow: func(c redis.Conn, t time.Time) error {
  48. _, err := c.Do("PING")
  49. return err
  50. },
  51. }, nil
  52. }
  53. func (h *Hub) conn() error {
  54. dialOpts := []redis.DialOption{
  55. redis.DialConnectTimeout(5 * time.Second),
  56. redis.DialReadTimeout(50 * time.Millisecond),
  57. redis.DialWriteTimeout(50 * time.Millisecond),
  58. }
  59. nodes := viper.GetStringSlice("redis.nodes")
  60. if nil != nodes && len(nodes) > 0 { // 集群
  61. cluster := &redisc.Cluster{
  62. StartupNodes: nodes,
  63. DialOptions: dialOpts,
  64. CreatePool: h.createPool,
  65. }
  66. h.cluster = cluster
  67. } else { // 单点
  68. var pool *redis.Pool
  69. host := viper.GetString("redis.host")
  70. password := viper.GetString("redis.password")
  71. if len(strings.TrimSpace(password)) > 0 {
  72. dialOpts = append(dialOpts, redis.DialPassword(strings.TrimSpace(password)))
  73. }
  74. pool, _ = h.createPool(host, dialOpts...)
  75. h.pool = pool
  76. }
  77. return nil
  78. }
  79. func (h *Hub) test() error {
  80. // 连接测试
  81. conn, err := h.Get()
  82. if nil != err {
  83. return err
  84. }
  85. defer func(conn redis.Conn) {
  86. _ = conn.Close()
  87. }(conn)
  88. if reply, err := redis.String(conn.Do("PING")); err != nil || reply != "PONG" {
  89. if err != nil {
  90. h.LOG().Warnf("Can not connect to redis: %s", err.Error())
  91. } else {
  92. h.LOG().Warnf("Can not connect to redis: %s", reply)
  93. }
  94. return err
  95. }
  96. h.LOG().Info("Redis connected")
  97. return nil
  98. }
  99. func (h *Hub) closeWait() {
  100. go func(h *Hub) {
  101. defer utils.DefaultGoroutineRecover(nil, `Redis连接池关闭`)
  102. var c chan os.Signal
  103. var s os.Signal
  104. c = make(chan os.Signal, 1)
  105. signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGKILL)
  106. for {
  107. s = <-c
  108. switch s {
  109. case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGKILL:
  110. if err := h.Close(); nil != err {
  111. h.LOG().Error("Close redis connection failed:", err.Error())
  112. }
  113. h.LOG().Info("Redis connection closed")
  114. return
  115. default:
  116. return
  117. }
  118. }
  119. }(h)
  120. }
  121. func (h *Hub) Close() error {
  122. var err error
  123. if nil != h.cluster {
  124. err = h.cluster.Close()
  125. } else if nil != h.pool {
  126. err = h.pool.Close()
  127. }
  128. return err
  129. }
  130. func (h *Hub) Do(cmd string, args ...interface{}) (interface{}, error) {
  131. conn, err := h.Get()
  132. if nil != err {
  133. return nil, err
  134. }
  135. defer func(conn redis.Conn) {
  136. _ = conn.Close()
  137. }(conn)
  138. if nil == conn {
  139. return nil, ErrRedisConnNil
  140. } else {
  141. reply, err := conn.Do(cmd, args...)
  142. if nil != err {
  143. return nil, err
  144. }
  145. return reply, nil
  146. }
  147. }
  148. const (
  149. ErrRedisConnNil = ErrRedis("redis conn nil")
  150. )
  151. type ErrRedis string
  152. func (err ErrRedis) Error() string {
  153. return string(err)
  154. }
  155. func (h *Hub) Get() (redis.Conn, error) {
  156. var err error
  157. h.once.Do(func() {
  158. e := h.conn()
  159. if nil != e {
  160. err = e
  161. } else {
  162. h.closeWait()
  163. }
  164. })
  165. if nil != err {
  166. return nil, err
  167. }
  168. if nil != h.pool {
  169. return h.pool.Get(), nil
  170. } else if nil != h.cluster {
  171. return h.cluster.Get(), nil
  172. } else {
  173. return nil, ErrRedisConnNil
  174. }
  175. }