lock.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package trylock
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/labring/aiproxy/core/common"
  7. log "github.com/sirupsen/logrus"
  8. )
  9. var memRecord = sync.Map{}
  10. func init() {
  11. go cleanMemLock()
  12. }
  13. func cleanMemLock() {
  14. ticker := time.NewTicker(30 * time.Second)
  15. defer ticker.Stop()
  16. for now := range ticker.C {
  17. memRecord.Range(func(key, value any) bool {
  18. exp, ok := value.(time.Time)
  19. if !ok || now.After(exp) {
  20. memRecord.CompareAndDelete(key, value)
  21. }
  22. return true
  23. })
  24. }
  25. }
  26. func MemLock(key string, expiration time.Duration) bool {
  27. now := time.Now()
  28. newExpiration := now.Add(expiration)
  29. for {
  30. actual, loaded := memRecord.LoadOrStore(key, newExpiration)
  31. if !loaded {
  32. return true
  33. }
  34. oldExpiration, ok := actual.(time.Time)
  35. if !ok {
  36. memRecord.CompareAndDelete(key, actual)
  37. continue
  38. }
  39. if now.After(oldExpiration) {
  40. if memRecord.CompareAndSwap(key, actual, newExpiration) {
  41. return true
  42. }
  43. continue
  44. }
  45. return false
  46. }
  47. }
  48. func Lock(key string, expiration time.Duration) bool {
  49. if !common.RedisEnabled {
  50. return MemLock(key, expiration)
  51. }
  52. ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  53. defer cancel()
  54. result, err := common.RDB.SetNX(ctx, common.RedisKey(key), true, expiration).Result()
  55. if err != nil {
  56. if MemLock("lockerror", time.Second*3) {
  57. log.Errorf("try notify error: %v", err)
  58. }
  59. return MemLock(key, expiration)
  60. }
  61. return result
  62. }