|
- package svc
-
- import (
- "applet/app/md"
- "applet/app/utils"
- "applet/app/utils/cache"
- "errors"
- "fmt"
- "math/rand"
- "reflect"
- "time"
- )
-
- const redisMutexLockExpTime = 15
-
- // TryGetDistributedLock 分布式锁获取
- // requestId 用于标识请求客户端,可以是随机字符串,需确保唯一
- func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool {
- if isNegative { // 多次尝试获取
- retry := 1
- for {
- ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
- // 获取锁成功
- if err == nil && ok == "OK" {
- return true
- }
- // 尝试多次没获取成功
- if retry > 10 {
- return false
- }
- time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
- retry += 1
- }
- } else { // 只尝试一次
- ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
- // 获取锁成功
- if err == nil && ok == "OK" {
- return true
- }
-
- return false
- }
- }
-
- // ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型
- func ReleaseDistributedLock(lockKey, requestId string) (bool, error) {
- luaScript := `
- if redis.call("get",KEYS[1]) == ARGV[1]
- then
- return redis.call("del",KEYS[1])
- else
- return 0
- end`
-
- do, err := cache.Do("eval", luaScript, 1, lockKey, requestId)
- fmt.Println(reflect.TypeOf(do))
- fmt.Println(do)
-
- if utils.AnyToInt64(do) == 1 {
- return true, err
- } else {
- return false, err
- }
- }
-
- func GetDistributedLockRequestId(prefix string) string {
- return prefix + utils.IntToStr(rand.Intn(100000000))
- }
-
- func HandleLimiterDistributedLock(ip, requestIdPrefix string) (cb func(), err error) {
- balanceLockKey := fmt.Sprintf(md.AppLimiterLock, ip)
- requestId := GetDistributedLockRequestId(requestIdPrefix)
- balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true)
- if !balanceLockOk {
- return nil, errors.New("系统繁忙,请稍后再试")
- }
-
- cb = func() {
- _, _ = ReleaseDistributedLock(balanceLockKey, requestId)
- }
-
- return cb, nil
- }
|