123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- 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)
- }
|