Browse Source

#1494

add lock
tags/v1.22.2.2^2
chenyifan01 3 years ago
parent
commit
acae810f74
5 changed files with 89 additions and 8 deletions
  1. +29
    -6
      modules/auth/wechat/access_token.go
  2. +1
    -1
      modules/auth/wechat/qr_code.go
  3. +16
    -1
      modules/redis/redis_client/client.go
  4. +3
    -0
      modules/redis/redis_key/wechat_redis_key.go
  5. +40
    -0
      modules/redis/redis_lock/lock.go

+ 29
- 6
modules/auth/wechat/access_token.go View File

@@ -3,11 +3,14 @@ package wechat
import ( import (
"code.gitea.io/gitea/modules/redis/redis_client" "code.gitea.io/gitea/modules/redis/redis_client"
"code.gitea.io/gitea/modules/redis/redis_key" "code.gitea.io/gitea/modules/redis/redis_key"
"code.gitea.io/gitea/modules/redis/redis_lock"
"time" "time"
) )


const EMPTY_REDIS_VAL = "Nil" const EMPTY_REDIS_VAL = "Nil"


var accessTokenLock = redis_lock.NewDistributeLock()

func GetWechatAccessToken() string { func GetWechatAccessToken() string {
token, _ := redis_client.Get(redis_key.WechatAccessTokenKey()) token, _ := redis_client.Get(redis_key.WechatAccessTokenKey())
if token != "" { if token != "" {
@@ -17,14 +20,37 @@ func GetWechatAccessToken() string {
live, _ := redis_client.TTL(redis_key.WechatAccessTokenKey()) live, _ := redis_client.TTL(redis_key.WechatAccessTokenKey())
//refresh wechat access token when expire time less than 5 minutes //refresh wechat access token when expire time less than 5 minutes
if live > 0 && live < 300 { if live > 0 && live < 300 {
refreshAccessTokenCache()
refreshAccessToken()
} }
return token return token
} }
return refreshAccessTokenCache()
return refreshAndGetAccessToken()
}

func refreshAccessToken() {
if ok := accessTokenLock.Lock(redis_key.AccessTokenLockKey(), 3*time.Second); ok {
defer accessTokenLock.UnLock(redis_key.AccessTokenLockKey())
callAccessTokenAndUpdateCache()
}
}

func refreshAndGetAccessToken() string {
if ok := accessTokenLock.LockWithWait(redis_key.AccessTokenLockKey(), 3*time.Second, 3*time.Second); ok {
defer accessTokenLock.UnLock(redis_key.AccessTokenLockKey())
token, _ := redis_client.Get(redis_key.WechatAccessTokenKey())
if token != "" {
if token == EMPTY_REDIS_VAL {
return ""
}
return token
}
return callAccessTokenAndUpdateCache()
}
return ""

} }


func refreshAccessTokenCache() string {
func callAccessTokenAndUpdateCache() string {
r := callAccessToken() r := callAccessToken()


var token string var token string
@@ -36,9 +62,6 @@ func refreshAccessTokenCache() string {
redis_client.Setex(redis_key.WechatAccessTokenKey(), EMPTY_REDIS_VAL, 10*time.Second) redis_client.Setex(redis_key.WechatAccessTokenKey(), EMPTY_REDIS_VAL, 10*time.Second)
return "" return ""
} }

redis_client.Setex(redis_key.WechatAccessTokenKey(), token, time.Duration(r.Expires_in)*time.Second) redis_client.Setex(redis_key.WechatAccessTokenKey(), token, time.Duration(r.Expires_in)*time.Second)

return token return token

} }

+ 1
- 1
modules/auth/wechat/qr_code.go View File

@@ -6,7 +6,7 @@ func GetWechatQRCode4Bind(sceneStr string) *QRCodeResponse {
result, retryFlag := callQRCodeCreate(sceneStr) result, retryFlag := callQRCodeCreate(sceneStr)
if retryFlag { if retryFlag {
log.Info("retry wechat qr-code calling,sceneStr=%s", sceneStr) log.Info("retry wechat qr-code calling,sceneStr=%s", sceneStr)
refreshAccessTokenCache()
refreshAccessToken()
result, _ = callQRCodeCreate(sceneStr) result, _ = callQRCodeCreate(sceneStr)
} }
return result return result


+ 16
- 1
modules/redis/redis_client/client.go View File

@@ -9,7 +9,6 @@ import (
"time" "time"
) )


//todo redis连接池
func Setex(key, value string, timeout time.Duration) (bool, error) { func Setex(key, value string, timeout time.Duration) (bool, error) {
redisClient := labelmsg.Get() redisClient := labelmsg.Get()
defer redisClient.Close() defer redisClient.Close()
@@ -26,6 +25,22 @@ func Setex(key, value string, timeout time.Duration) (bool, error) {


} }


func Setnx(key, value string, timeout time.Duration) (bool, error) {
redisClient := labelmsg.Get()
defer redisClient.Close()

seconds := int(math.Floor(timeout.Seconds()))
reply, err := redisClient.Do("SET", key, value, "NX", "EX", seconds)
if err != nil {
return false, err
}
if reply != "OK" {
return false, nil
}
return true, nil

}

func Get(key string) (string, error) { func Get(key string) (string, error) {
redisClient := labelmsg.Get() redisClient := labelmsg.Get()
defer redisClient.Close() defer redisClient.Close()


+ 3
- 0
modules/redis/redis_key/wechat_redis_key.go View File

@@ -9,3 +9,6 @@ func WechatBindingUserIdKey(sceneStr string) string {
func WechatAccessTokenKey() string { func WechatAccessTokenKey() string {
return KeyJoin(PREFIX, "access_token") return KeyJoin(PREFIX, "access_token")
} }
func AccessTokenLockKey() string {
return KeyJoin(PREFIX, "access_token_lock")
}

+ 40
- 0
modules/redis/redis_lock/lock.go View File

@@ -0,0 +1,40 @@
package redis_lock

import (
"code.gitea.io/gitea/modules/redis/redis_client"
"time"
)

type DistributeLock struct {
}

func NewDistributeLock() *DistributeLock {
return &DistributeLock{}
}

func (lock *DistributeLock) Lock(lockKey string, expireTime time.Duration) bool {
isOk, _ := redis_client.Setnx(lockKey, "", expireTime)
return isOk
}

func (lock *DistributeLock) LockWithWait(lockKey string, expireTime time.Duration, waitTime time.Duration) bool {
start := time.Now().UnixMilli()
duration := waitTime.Milliseconds()
for {
isOk, _ := redis_client.Setnx(lockKey, "", expireTime)
if isOk {
return true
}
if time.Now().UnixMilli()-start > duration {
return false
}
time.Sleep(50 * time.Millisecond)
}

return false
}

func (lock *DistributeLock) UnLock(lockKey string) error {
_, err := redis_client.Del(lockKey)
return err
}

Loading…
Cancel
Save