distrubtLock.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package lock
  2. import (
  3. "context"
  4. "errors"
  5. "eta/eta_api/utils"
  6. "fmt"
  7. "github.com/go-redis/redis/v8"
  8. "time"
  9. )
  10. const (
  11. lockName = "lock:"
  12. )
  13. var (
  14. ctx = context.Background()
  15. )
  16. func AcquireLock(key string, expiration int, Holder string) bool {
  17. script := redis.NewScript(`local key = KEYS[1]
  18. local clientId = ARGV[1]
  19. local expiration = tonumber(ARGV[2])
  20. if redis.call("EXISTS", key) == 0 then
  21. redis.call("SET", key, clientId, "EX", expiration)
  22. return 1
  23. else
  24. return 0
  25. end`)
  26. lockey := fmt.Sprintf("%s%s", lockName, key)
  27. result, err := script.Run(ctx, utils.Rc.RedisClient(), []string{lockey}, Holder, expiration).Int()
  28. if err != nil {
  29. fmt.Printf("加锁失败:err: %v", err)
  30. return false
  31. }
  32. if result == 1 {
  33. return true
  34. }
  35. return false
  36. }
  37. func TryLock(key string, expiration int, Holder string, timeout time.Duration) error {
  38. script := redis.NewScript(`
  39. local session = ARGV[1]
  40. local current = redis.call("hget", KEYS[1], session)
  41. if current then
  42. local count = tonumber(current)
  43. if count > 0 then
  44. redis.call("hincrby", KEYS[1], session, 1)
  45. return 1
  46. else
  47. return 0
  48. end
  49. else
  50. redis.call("hset", KEYS[1], session, 1)
  51. redis.call("expire", KEYS[1], 10)
  52. return 1
  53. end
  54. `)
  55. start := time.Now()
  56. for {
  57. result, err := script.Run(context.Background(), utils.Rc.RedisClient(), []string{key}, Holder).Result()
  58. if err != nil {
  59. return err
  60. }
  61. if result.(int64) == 1 {
  62. //go renewLock()
  63. return nil
  64. }
  65. if time.Since(start) >= timeout {
  66. return errors.New("获取锁超时")
  67. }
  68. time.Sleep(200 * time.Millisecond)
  69. }
  70. }
  71. //
  72. //func renewLock() {
  73. // for {
  74. // time.Sleep(5 * time.Second)
  75. //
  76. // script := redis.NewScript(1, `
  77. // local session = ARGV[1]
  78. // local current = redis.call("hget", KEYS[1], session)
  79. // if current then
  80. // local count = tonumber(current)
  81. // if count > 0 then
  82. // redis.call("expire", KEYS[1], 10)
  83. // return 1
  84. // else
  85. // return 0
  86. // end
  87. // else
  88. // return 0
  89. // end
  90. // `)
  91. //
  92. // result, err := script.Run(r.ctx, r.client, []string{r.key}, r.session).Result()
  93. // if err != nil {
  94. // fmt.Println("Failed to renew lock:", err)
  95. // return
  96. // }
  97. //
  98. // if result.(int64) == 0 {
  99. // fmt.Println("Lock not held by current client, stopping renewal")
  100. // return
  101. // }
  102. // }
  103. //}
  104. func ReleaseLock(key string, holder string) bool {
  105. script := redis.NewScript(`
  106. if redis.call("get", KEYS[1]) == ARGV[1] then
  107. return redis.call("del", KEYS[1])
  108. else
  109. return 0
  110. end
  111. `)
  112. lockey := fmt.Sprintf("%s%s", lockName, key)
  113. result, err := script.Run(ctx, utils.Rc.RedisClient(), []string{lockey}, holder).Int()
  114. if err != nil {
  115. fmt.Printf("解锁失败:err: %v", err)
  116. return false
  117. }
  118. if result == 1 {
  119. return true
  120. }
  121. return false
  122. }