package lock import ( "context" "eta/eta_api/utils" "fmt" "github.com/go-redis/redis/v8" "time" ) const ( lockName = "lock:" ) var ( ctx = context.Background() ) func AcquireLock(key string, expiration int, Holder string) bool { script := redis.NewScript(`local key = KEYS[1] local clientId = ARGV[1] local expiration = tonumber(ARGV[2]) if redis.call("EXISTS", key) == 0 then redis.call("SET", key, clientId, "EX", expiration) return 1 else return 0 end`) lockey := fmt.Sprintf("%s%s", lockName, key) result, err := script.Run(ctx, utils.Rc.RedisClient(), []string{lockey}, Holder, expiration).Int() if err != nil { fmt.Printf("加锁失败:err: %v", err) return false } if result == 1 { return true } return false } func TryLock(key string, expiration int, Holder string, timeout time.Duration) error { redisCtx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() for { select { case <-redisCtx.Done(): return fmt.Errorf("等待超时") default: if AcquireLock(key, expiration, Holder) { // 启动异步续约 go renewLock(key, Holder, expiration) return nil } // 等待重试 time.Sleep(50 * time.Millisecond) } } } func renewLock(key, holder string, expiration int) { for { time.Sleep(5 * time.Second) script := redis.NewScript(` local key = KEYS[1] local clientId = ARGV[1] local expiration = tonumber(ARGV[2]) if redis.call("get", KEYS[1]) == ARGV[1] then redis.call("SET", key, clientId, "EX", expiration) return 1 else return 0 end `) lockey := fmt.Sprintf("%s%s", lockName, key) result, err := script.Run(context.Background(), utils.Rc.RedisClient(), []string{lockey}, holder, expiration).Result() if err != nil { fmt.Println("锁续期失败:", err) return } if result.(int64) == 0 { fmt.Println("持有者变更,停止监听") return } fmt.Printf("锁续期成功") } } func ReleaseLock(key string, holder string) bool { script := redis.NewScript(` if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end `) lockey := fmt.Sprintf("%s%s", lockName, key) result, err := script.Run(ctx, utils.Rc.RedisClient(), []string{lockey}, holder).Int() if err != nil { fmt.Printf("解锁失败:err: %v", err) return false } if result == 1 { return true } return false }