redis.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package dao
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/pkg/errors"
  6. "go-common/library/cache/redis"
  7. "go-common/library/log"
  8. "time"
  9. )
  10. var (
  11. UnLockGetWrong = "UnLockGetWrong"
  12. LockFailed = "LockFailed"
  13. UserWalletPrefix = "user_wallet_lock_uid_"
  14. ErrUnLockGet = errors.New(UnLockGetWrong)
  15. ErrLockFailed = errors.New(LockFailed)
  16. )
  17. func (d *Dao) IsLockFailedError(err error) bool {
  18. return err == ErrLockFailed
  19. }
  20. func lockKey(k string) string {
  21. return "wallet_lock_key:" + k
  22. }
  23. /*
  24. ttl ms
  25. retry 重试次数
  26. retryDelay us
  27. */
  28. func (d *Dao) Lock(ctx context.Context, key string, ttl int, retry int, retryDelay int) (err error, gotLock bool, lockValue string) {
  29. if retry <= 0 {
  30. retry = 1
  31. }
  32. lockValue = "locked:" + randomString(5)
  33. retryTimes := 0
  34. conn := d.redis.Get(ctx)
  35. defer conn.Close()
  36. realKey := lockKey(key)
  37. for ; retryTimes < retry; retryTimes++ {
  38. var res interface{}
  39. res, err = conn.Do("SET", realKey, lockValue, "PX", ttl, "NX")
  40. if err != nil {
  41. log.Error("redis_lock failed:%s:%s", realKey, err.Error())
  42. break
  43. }
  44. if res != nil {
  45. gotLock = true
  46. break
  47. }
  48. time.Sleep(time.Duration(retryDelay * 1000))
  49. }
  50. return
  51. }
  52. func (d *Dao) UnLock(ctx context.Context, key string, lockValue string) (err error) {
  53. conn := d.redis.Get(ctx)
  54. defer conn.Close()
  55. realKey := lockKey(key)
  56. res, err := redis.String(conn.Do("GET", realKey))
  57. if err != nil {
  58. return
  59. }
  60. if res != lockValue {
  61. err = ErrUnLockGet
  62. return
  63. }
  64. _, err = conn.Do("DEL", realKey)
  65. return
  66. }
  67. func (d *Dao) ForceUnLock(ctx context.Context, key string) (err error) {
  68. realKey := lockKey(key)
  69. conn := d.redis.Get(ctx)
  70. defer conn.Close()
  71. _, err = conn.Do("DEL", realKey)
  72. return
  73. }
  74. func (d *Dao) LockTransactionId(ctx context.Context, tid string) (err error) {
  75. err, gotLock, _ := d.Lock(ctx, tid, 300*1000, 0, 200000)
  76. if err != nil {
  77. return
  78. }
  79. if !gotLock {
  80. err = ErrLockFailed
  81. }
  82. return
  83. }
  84. func (d *Dao) LockUser(ctx context.Context, uid int64) (err error, gotLock bool, lockValue string) {
  85. lockTime := 600
  86. retry := 1
  87. retryDelay := 10
  88. return d.Lock(ctx, getUserLockKey(uid), lockTime*1000, retry, retryDelay*1000)
  89. }
  90. func (d *Dao) UnLockUser(ctx context.Context, uid int64, lockValue string) error {
  91. return d.UnLock(ctx, getUserLockKey(uid), lockValue)
  92. }
  93. func getUserLockKey(uid int64) string {
  94. return fmt.Sprintf("%s%v", UserWalletPrefix, uid)
  95. }