95 lines
1.6 KiB
Go
95 lines
1.6 KiB
Go
package uniquex
|
|
|
|
// Version: 2023年6月12日18:59:16
|
|
|
|
/**
|
|
说明:
|
|
1. 这是基于redis的全局锁
|
|
2. 只要没释放锁会自动的续期,不用考虑锁被提前释放的问题
|
|
3. 允许自定义超时时间
|
|
**/
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
uuid "github.com/satori/go.uuid"
|
|
|
|
"github.com/go-redis/redis/v8"
|
|
)
|
|
|
|
type uniquex struct {
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
redis *redis.Client
|
|
uniqueKey string
|
|
uuid string
|
|
}
|
|
|
|
const tokenValidTime = time.Second * 5
|
|
|
|
func NewUniquex(ctx context.Context, redis *redis.Client, uniqueKey string) *uniquex {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
// 获取Token
|
|
return &uniquex{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
redis: redis,
|
|
uniqueKey: uniqueKey,
|
|
uuid: uuid.NewV4().String(),
|
|
}
|
|
}
|
|
|
|
func (u *uniquex) Lock() error {
|
|
// 获取Token
|
|
b, err := u.redis.SetNX(u.ctx, u.uniqueKey, u.uuid, tokenValidTime).Result()
|
|
if !b {
|
|
return err
|
|
}
|
|
|
|
go u.refreshToken()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (u *uniquex) Unlock() {
|
|
u.cancel()
|
|
|
|
// 释放Token
|
|
script := `
|
|
local token = redis.call('get',KEYS[1]);
|
|
if token == ARGV[1]
|
|
then
|
|
redis.call('del',KEYS[1]);
|
|
return 'SUCCESS';
|
|
end;
|
|
return 'ERROR'
|
|
`
|
|
u.redis.Eval(u.ctx, script, []string{u.uniqueKey}, u.uuid)
|
|
|
|
return
|
|
}
|
|
|
|
// 刷新Token
|
|
func (u *uniquex) refreshToken() {
|
|
script := `
|
|
local token = redis.call('get',KEYS[1])
|
|
if token == ARGV[1]
|
|
then
|
|
redis.call('set',KEYS[1],ARGV[2],ARGV[1]);
|
|
return 'SUCCESS';
|
|
end;
|
|
return 'ERROR';
|
|
`
|
|
for {
|
|
time.Sleep(time.Second)
|
|
select {
|
|
case <-u.ctx.Done():
|
|
return
|
|
default:
|
|
}
|
|
u.redis.Eval(u.ctx, script, []string{u.uniqueKey}, u.uuid, tokenValidTime.Seconds())
|
|
}
|
|
}
|