lock.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package global
  2. import (
  3. "context"
  4. "designs/utils"
  5. "github.com/go-redis/redis/v8"
  6. "time"
  7. )
  8. type Interface interface {
  9. Get() bool
  10. Block(seconds int64) bool
  11. Release() bool
  12. ForceRelease()
  13. }
  14. type lock struct {
  15. context context.Context
  16. name string
  17. owner string
  18. seconds int64
  19. }
  20. const releaseLockLuaScript = `
  21. if redis.call("get",KEYS[1]) == ARGV[1] then
  22. return redis.call("del",KEYS[1])
  23. else
  24. return 0
  25. end
  26. `
  27. func Lock(name string, seconds int64) Interface {
  28. return &lock{
  29. context.Background(),
  30. name,
  31. utils.RandString(16),
  32. seconds,
  33. }
  34. }
  35. func (l *lock) Get() bool {
  36. return App.Redis.SetNX(l.context, l.name, l.owner, time.Duration(l.seconds)*time.Second).Val()
  37. }
  38. func (l *lock) Block(seconds int64) bool {
  39. timer := time.After(time.Duration(seconds) * time.Second)
  40. for {
  41. select {
  42. case <-timer:
  43. return false
  44. default:
  45. if l.Get() {
  46. return true
  47. }
  48. time.Sleep(time.Duration(1) * time.Second)
  49. }
  50. }
  51. }
  52. func (l *lock) Release() bool {
  53. luaScript := redis.NewScript(releaseLockLuaScript)
  54. result := luaScript.Run(l.context, App.Redis, []string{l.name}, l.owner).Val().(int64)
  55. return result != 0
  56. }
  57. func (l *lock) ForceRelease() {
  58. App.Redis.Del(l.context, l.name).Val()
  59. }