Files
timerx/lockx/lockx.go
T

121 lines
2.2 KiB
Go
Raw Normal View History

2023-08-27 23:39:58 +08:00
package lockx
import (
"context"
"fmt"
2023-08-29 10:27:36 +08:00
"log"
2023-08-27 23:39:58 +08:00
"time"
"github.com/go-redis/redis/v8"
)
// 全局锁
type globalLock struct {
redis *redis.Client
ctx context.Context
2023-09-03 00:30:22 +08:00
cancel context.CancelFunc
2023-08-27 23:39:58 +08:00
uniqueKey string
value string
}
func NewGlobalLock(ctx context.Context, red *redis.Client, uniqueKey string) *globalLock {
2023-09-03 00:30:22 +08:00
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
2023-08-27 23:39:58 +08:00
return &globalLock{
redis: red,
ctx: ctx,
2023-09-03 00:30:22 +08:00
cancel: cancel,
2023-08-27 23:39:58 +08:00
uniqueKey: uniqueKey,
value: fmt.Sprintf("%d", time.Now().UnixNano()),
}
}
// 获取锁
func (g *globalLock) Lock() bool {
script := `
2023-09-02 12:19:27 +08:00
local token = redis.call('get',KEYS[1])
if token == false
then
return redis.call('set',KEYS[1],ARGV[1],'EX',ARGV[2])
end
return 'ERROR'
2023-08-27 23:39:58 +08:00
`
2023-09-02 13:32:04 +08:00
resp, err := g.redis.Eval(g.ctx, script, []string{g.uniqueKey}, g.value, 5).Result()
2023-08-29 10:27:36 +08:00
if resp != "OK" {
2023-09-02 12:19:27 +08:00
_ = err
2023-09-02 13:32:04 +08:00
log.Println("globalLock Lock", resp, err, g.uniqueKey, g.value)
2023-08-29 10:27:36 +08:00
}
2023-09-03 00:30:22 +08:00
if resp == "OK" {
g.refresh()
return true
}
return false
2023-08-27 23:39:58 +08:00
}
// 尝试获取锁
func (g *globalLock) Try(limitTimes int) bool {
for i := 0; i < limitTimes; i++ {
if g.Lock() {
return true
}
time.Sleep(time.Millisecond * 100)
}
return false
}
// 删除锁
func (g *globalLock) Unlock() bool {
script := `
local token = redis.call('get',KEYS[1])
if token == ARGV[1]
then
2023-09-02 12:19:27 +08:00
redis.call('del',KEYS[1])
return 'OK'
2023-08-27 23:39:58 +08:00
end
2023-09-02 12:19:27 +08:00
return 'ERROR'
2023-08-27 23:39:58 +08:00
`
2023-08-29 10:27:36 +08:00
resp, err := g.redis.Eval(g.ctx, script, []string{g.uniqueKey}, g.value).Result()
if resp != "OK" {
2023-09-02 12:19:27 +08:00
log.Println("globalLock Unlock", resp, err, g.uniqueKey, g.value)
2023-08-29 10:27:36 +08:00
}
2023-09-09 23:32:37 +08:00
g.cancel()
2023-09-03 00:30:22 +08:00
return false
2023-08-27 23:39:58 +08:00
}
// 刷新锁
2023-09-03 00:30:22 +08:00
func (g *globalLock) refresh() {
2023-08-27 23:39:58 +08:00
go func() {
t := time.NewTicker(time.Second)
for {
select {
case <-t.C:
2023-09-03 00:30:22 +08:00
g.refreshExec()
case <-g.ctx.Done():
2023-08-27 23:39:58 +08:00
t.Stop()
return
}
}
}()
}
2023-09-03 00:30:22 +08:00
func (g *globalLock) refreshExec() bool {
2023-08-27 23:39:58 +08:00
script := `
local token = redis.call('get',KEYS[1])
if token == ARGV[1]
then
2023-08-29 10:27:36 +08:00
redis.call('set',KEYS[1],ARGV[1],'EX',ARGV[2])
return 'OK'
2023-08-27 23:39:58 +08:00
end
2023-09-02 12:19:27 +08:00
return 'ERROR'
2023-08-27 23:39:58 +08:00
`
2023-08-29 10:27:36 +08:00
resp, err := g.redis.Eval(g.ctx, script, []string{g.uniqueKey}, g.value, 5).Result()
if resp != "OK" {
2023-09-02 12:19:27 +08:00
log.Println("globalLock refresh", resp, err, g.uniqueKey, g.value)
2023-08-29 10:27:36 +08:00
}
2023-08-27 23:39:58 +08:00
return resp == "OK"
}