go-common/app/service/live/wallet/dao/redis.go
2019-04-22 18:49:16 +08:00

116 lines
2.3 KiB
Go

package dao
import (
"context"
"fmt"
"github.com/pkg/errors"
"go-common/library/cache/redis"
"go-common/library/log"
"time"
)
var (
UnLockGetWrong = "UnLockGetWrong"
LockFailed = "LockFailed"
UserWalletPrefix = "user_wallet_lock_uid_"
ErrUnLockGet = errors.New(UnLockGetWrong)
ErrLockFailed = errors.New(LockFailed)
)
func (d *Dao) IsLockFailedError(err error) bool {
return err == ErrLockFailed
}
func lockKey(k string) string {
return "wallet_lock_key:" + k
}
/*
ttl ms
retry 重试次数
retryDelay us
*/
func (d *Dao) Lock(ctx context.Context, key string, ttl int, retry int, retryDelay int) (err error, gotLock bool, lockValue string) {
if retry <= 0 {
retry = 1
}
lockValue = "locked:" + randomString(5)
retryTimes := 0
conn := d.redis.Get(ctx)
defer conn.Close()
realKey := lockKey(key)
for ; retryTimes < retry; retryTimes++ {
var res interface{}
res, err = conn.Do("SET", realKey, lockValue, "PX", ttl, "NX")
if err != nil {
log.Error("redis_lock failed:%s:%s", realKey, err.Error())
break
}
if res != nil {
gotLock = true
break
}
time.Sleep(time.Duration(retryDelay * 1000))
}
return
}
func (d *Dao) UnLock(ctx context.Context, key string, lockValue string) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
realKey := lockKey(key)
res, err := redis.String(conn.Do("GET", realKey))
if err != nil {
return
}
if res != lockValue {
err = ErrUnLockGet
return
}
_, err = conn.Do("DEL", realKey)
return
}
func (d *Dao) ForceUnLock(ctx context.Context, key string) (err error) {
realKey := lockKey(key)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("DEL", realKey)
return
}
func (d *Dao) LockTransactionId(ctx context.Context, tid string) (err error) {
err, gotLock, _ := d.Lock(ctx, tid, 300*1000, 0, 200000)
if err != nil {
return
}
if !gotLock {
err = ErrLockFailed
}
return
}
func (d *Dao) LockUser(ctx context.Context, uid int64) (err error, gotLock bool, lockValue string) {
lockTime := 600
retry := 1
retryDelay := 10
return d.Lock(ctx, getUserLockKey(uid), lockTime*1000, retry, retryDelay*1000)
}
func (d *Dao) UnLockUser(ctx context.Context, uid int64, lockValue string) error {
return d.UnLock(ctx, getUserLockKey(uid), lockValue)
}
func getUserLockKey(uid int64) string {
return fmt.Sprintf("%s%v", UserWalletPrefix, uid)
}