redis.go 8.5 KB

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