redis.go 8.8 KB

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