redis.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. package cache
  2. import (
  3. "context"
  4. "time"
  5. "git.bvbej.com/bvbej/base-golang/pkg/errors"
  6. "git.bvbej.com/bvbej/base-golang/pkg/time_parse"
  7. "git.bvbej.com/bvbej/base-golang/pkg/trace"
  8. "github.com/go-redis/redis/v8"
  9. )
  10. type Option func(*option)
  11. type Trace = trace.T
  12. type option struct {
  13. Trace *trace.Trace
  14. Redis *trace.Redis
  15. }
  16. type RedisConfig struct {
  17. Addr string `yaml:"addr"`
  18. Pass string `yaml:"pass"`
  19. DB int `yaml:"db"`
  20. MaxRetries int `yaml:"maxRetries"` // 最大重试次数
  21. PoolSize int `yaml:"poolSize"` // Redis连接池大小
  22. MinIdleConn int `yaml:"minIdleConn"` // 最小空闲连接数
  23. }
  24. func newOption() *option {
  25. return &option{}
  26. }
  27. var _ Repo = (*cacheRepo)(nil)
  28. type Repo interface {
  29. i()
  30. Client() *redis.Client
  31. Set(key, value string, ttl time.Duration, options ...Option) error
  32. Get(key string, options ...Option) (string, error)
  33. TTL(key string) (time.Duration, error)
  34. Expire(key string, ttl time.Duration) bool
  35. ExpireAt(key string, ttl time.Time) bool
  36. Del(key string, options ...Option) bool
  37. Exists(keys ...string) bool
  38. Incr(key string, options ...Option) int64
  39. HGet(key, field string, options ...Option) (string, error)
  40. HSet(key, field, value string, options ...Option) error
  41. HDel(key, field string, options ...Option) error
  42. HGetAll(key string, options ...Option) (map[string]string, error)
  43. LPush(key, value string, options ...Option) error
  44. LLen(key string, options ...Option) (int64, error)
  45. BRPop(key string, timeout time.Duration, options ...Option) (string, error)
  46. Close() error
  47. }
  48. type cacheRepo struct {
  49. client *redis.Client
  50. ctx context.Context
  51. }
  52. func New(cfg RedisConfig) (Repo, error) {
  53. client := redis.NewClient(&redis.Options{
  54. Addr: cfg.Addr,
  55. Password: cfg.Pass,
  56. DB: cfg.DB,
  57. MaxRetries: cfg.MaxRetries,
  58. PoolSize: cfg.PoolSize,
  59. MinIdleConns: cfg.MinIdleConn,
  60. })
  61. ctx := context.TODO()
  62. if err := client.Ping(ctx).Err(); err != nil {
  63. return nil, errors.Wrap(err, "ping redis err")
  64. }
  65. return &cacheRepo{
  66. client: client,
  67. ctx: ctx,
  68. }, nil
  69. }
  70. func WithTrace(t Trace) Option {
  71. return func(opt *option) {
  72. if t != nil {
  73. opt.Trace = t.(*trace.Trace)
  74. opt.Redis = new(trace.Redis)
  75. }
  76. }
  77. }
  78. func (c *cacheRepo) i() {}
  79. func (c *cacheRepo) Client() *redis.Client {
  80. return c.client
  81. }
  82. func (c *cacheRepo) Set(key, value string, ttl time.Duration, options ...Option) error {
  83. ts := time.Now()
  84. opt := newOption()
  85. defer func() {
  86. if opt.Trace != nil {
  87. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  88. opt.Redis.Handle = "set"
  89. opt.Redis.Key = key
  90. opt.Redis.Value = value
  91. opt.Redis.TTL = ttl.Minutes()
  92. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  93. opt.Trace.AppendRedis(opt.Redis)
  94. }
  95. }()
  96. for _, f := range options {
  97. f(opt)
  98. }
  99. if err := c.client.Set(c.ctx, key, value, ttl).Err(); err != nil {
  100. return errors.Wrapf(err, "redis set key: %s err", key)
  101. }
  102. return nil
  103. }
  104. func (c *cacheRepo) Get(key string, options ...Option) (string, error) {
  105. ts := time.Now()
  106. opt := newOption()
  107. defer func() {
  108. if opt.Trace != nil {
  109. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  110. opt.Redis.Handle = "get"
  111. opt.Redis.Key = key
  112. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  113. opt.Trace.AppendRedis(opt.Redis)
  114. }
  115. }()
  116. for _, f := range options {
  117. f(opt)
  118. }
  119. value, err := c.client.Get(c.ctx, key).Result()
  120. if err != nil {
  121. return "", errors.Wrapf(err, "redis get key: %s err", key)
  122. }
  123. return value, nil
  124. }
  125. func (c *cacheRepo) TTL(key string) (time.Duration, error) {
  126. ttl, err := c.client.TTL(c.ctx, key).Result()
  127. if err != nil {
  128. return -1, errors.Wrapf(err, "redis get key: %s err", key)
  129. }
  130. return ttl, nil
  131. }
  132. func (c *cacheRepo) Expire(key string, ttl time.Duration) bool {
  133. ok, _ := c.client.Expire(c.ctx, key, ttl).Result()
  134. return ok
  135. }
  136. func (c *cacheRepo) ExpireAt(key string, ttl time.Time) bool {
  137. ok, _ := c.client.ExpireAt(c.ctx, key, ttl).Result()
  138. return ok
  139. }
  140. func (c *cacheRepo) Exists(keys ...string) bool {
  141. if len(keys) == 0 {
  142. return true
  143. }
  144. value, _ := c.client.Exists(c.ctx, keys...).Result()
  145. return value > 0
  146. }
  147. func (c *cacheRepo) Del(key string, options ...Option) bool {
  148. ts := time.Now()
  149. opt := newOption()
  150. defer func() {
  151. if opt.Trace != nil {
  152. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  153. opt.Redis.Handle = "del"
  154. opt.Redis.Key = key
  155. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  156. opt.Trace.AppendRedis(opt.Redis)
  157. }
  158. }()
  159. for _, f := range options {
  160. f(opt)
  161. }
  162. if key == "" {
  163. return true
  164. }
  165. value, _ := c.client.Del(c.ctx, key).Result()
  166. return value > 0
  167. }
  168. func (c *cacheRepo) Incr(key string, options ...Option) int64 {
  169. ts := time.Now()
  170. opt := newOption()
  171. defer func() {
  172. if opt.Trace != nil {
  173. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  174. opt.Redis.Handle = "incr"
  175. opt.Redis.Key = key
  176. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  177. opt.Trace.AppendRedis(opt.Redis)
  178. }
  179. }()
  180. for _, f := range options {
  181. f(opt)
  182. }
  183. value, _ := c.client.Incr(c.ctx, key).Result()
  184. return value
  185. }
  186. func (c *cacheRepo) HGet(key, field string, options ...Option) (string, error) {
  187. ts := time.Now()
  188. opt := newOption()
  189. defer func() {
  190. if opt.Trace != nil {
  191. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  192. opt.Redis.Handle = "hash get"
  193. opt.Redis.Key = key
  194. opt.Redis.Value = field
  195. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  196. opt.Trace.AppendRedis(opt.Redis)
  197. }
  198. }()
  199. for _, f := range options {
  200. f(opt)
  201. }
  202. value, err := c.client.HGet(c.ctx, key, field).Result()
  203. if err != nil {
  204. return "", errors.Wrapf(err, "redis hget key: %s field: %s", key, field)
  205. }
  206. return value, nil
  207. }
  208. func (c *cacheRepo) HSet(key, field, value string, options ...Option) error {
  209. ts := time.Now()
  210. opt := newOption()
  211. defer func() {
  212. if opt.Trace != nil {
  213. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  214. opt.Redis.Handle = "hash set"
  215. opt.Redis.Key = key
  216. opt.Redis.Value = field + "/" + value
  217. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  218. opt.Trace.AppendRedis(opt.Redis)
  219. }
  220. }()
  221. for _, f := range options {
  222. f(opt)
  223. }
  224. if err := c.client.HSet(c.ctx, key, field, value).Err(); err != nil {
  225. return errors.Wrapf(err, "redis set key: %s field: %s err", key, field)
  226. }
  227. return nil
  228. }
  229. func (c *cacheRepo) HDel(key, field string, options ...Option) error {
  230. ts := time.Now()
  231. opt := newOption()
  232. defer func() {
  233. if opt.Trace != nil {
  234. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  235. opt.Redis.Handle = "hash del"
  236. opt.Redis.Key = key
  237. opt.Redis.Value = field
  238. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  239. opt.Trace.AppendRedis(opt.Redis)
  240. }
  241. }()
  242. for _, f := range options {
  243. f(opt)
  244. }
  245. if err := c.client.HDel(c.ctx, key, field).Err(); err != nil {
  246. return errors.Wrapf(err, "redis del field: %s err", key, field)
  247. }
  248. return nil
  249. }
  250. func (c *cacheRepo) HGetAll(key string, options ...Option) (map[string]string, error) {
  251. ts := time.Now()
  252. opt := newOption()
  253. defer func() {
  254. if opt.Trace != nil {
  255. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  256. opt.Redis.Handle = "hash get all"
  257. opt.Redis.Key = key
  258. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  259. opt.Trace.AppendRedis(opt.Redis)
  260. }
  261. }()
  262. for _, f := range options {
  263. f(opt)
  264. }
  265. value, err := c.client.HGetAll(c.ctx, key).Result()
  266. if err != nil {
  267. return nil, errors.Wrapf(err, "redis get all key: %s err", key)
  268. }
  269. return value, nil
  270. }
  271. func (c *cacheRepo) LPush(key, value string, options ...Option) error {
  272. ts := time.Now()
  273. opt := newOption()
  274. defer func() {
  275. if opt.Trace != nil {
  276. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  277. opt.Redis.Handle = "list push"
  278. opt.Redis.Key = key
  279. opt.Redis.Value = value
  280. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  281. opt.Trace.AppendRedis(opt.Redis)
  282. }
  283. }()
  284. for _, f := range options {
  285. f(opt)
  286. }
  287. _, err := c.client.LPush(c.ctx, key, value).Result()
  288. if err != nil {
  289. return errors.Wrapf(err, "redis list push key: %s value: %s", key, value)
  290. }
  291. return nil
  292. }
  293. func (c *cacheRepo) LLen(key string, options ...Option) (int64, error) {
  294. ts := time.Now()
  295. opt := newOption()
  296. defer func() {
  297. if opt.Trace != nil {
  298. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  299. opt.Redis.Handle = "list len"
  300. opt.Redis.Key = key
  301. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  302. opt.Trace.AppendRedis(opt.Redis)
  303. }
  304. }()
  305. for _, f := range options {
  306. f(opt)
  307. }
  308. value, err := c.client.LLen(c.ctx, key).Result()
  309. if err != nil {
  310. return 0, errors.Wrapf(err, "redis list len key: %s err", key)
  311. }
  312. return value, nil
  313. }
  314. func (c *cacheRepo) BRPop(key string, timeout time.Duration, options ...Option) (string, error) {
  315. ts := time.Now()
  316. opt := newOption()
  317. defer func() {
  318. if opt.Trace != nil {
  319. opt.Redis.Timestamp = time_parse.CSTLayoutString()
  320. opt.Redis.Handle = "list brpop"
  321. opt.Redis.Key = key
  322. opt.Redis.TTL = timeout.Seconds()
  323. opt.Redis.CostSeconds = time.Since(ts).Seconds()
  324. opt.Trace.AppendRedis(opt.Redis)
  325. }
  326. }()
  327. for _, f := range options {
  328. f(opt)
  329. }
  330. value, err := c.client.BRPop(c.ctx, timeout, key).Result()
  331. if err != nil {
  332. return "", errors.Wrapf(err, "redis list len key: %s err", key)
  333. }
  334. return value[0], nil
  335. }
  336. func (c *cacheRepo) Close() error {
  337. return c.client.Close()
  338. }