redis.go 8.7 KB

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