goRedisDLM/redisLock/redis.go
2025-02-10 09:36:54 +08:00

90 lines
2.2 KiB
Go

package redisLock
import (
"context"
"log"
"time"
"github.com/go-redis/redis/v8"
)
type redisCommInfo struct {
key string
value string
ttl int
}
type RedisLock struct {
client *redis.Client
ctx context.Context
lockKeepAliveCh chan struct{}
kvt redisCommInfo
}
func CreateRedisLock(c *redis.Client, ctx context.Context, k, v string, ttl int) *RedisLock {
return &RedisLock{c, ctx, make(chan struct{}, 1), redisCommInfo{k, v, ttl}}
}
func (r *RedisLock) Lock() {
//for r.client.SetNX(r.ctx, r.kvt.key, r.kvt.value, time.Duration(r.kvt.ttl)*time.Second).Val() == false {
// time.Sleep(time.Millisecond * 20)
//}
script := `if redis.call('exists',KEYS[1]) == 0 or redis.call('hexists',KEYS[1],ARGV[1]) == 1 then
redis.call('hincrby',KEYS[1],ARGV[1],1)
redis.call('expire',KEYS[1],ARGV[2])
return 1
else
return 0
end`
for r.client.Eval(r.ctx, script, []string{r.kvt.key}, r.kvt.value, r.kvt.ttl).Val().(int64) == 0 {
time.Sleep(time.Millisecond * 20)
}
select {
case r.lockKeepAliveCh <- struct{}{}:
go r.autoReNewExpire()
default:
}
log.Printf("lock ok: %s,%s,%d\n", r.kvt.key, r.kvt.value, r.kvt.ttl)
}
func (r *RedisLock) Unlock() {
//if r.client.Get(r.ctx, r.kvt.key).Val() == r.kvt.value {
// r.client.Del(r.ctx, r.kvt.key)
//}
//script := "if (redis.call('get',KEYS[1]) == ARGV[1]) then return redis.call('del',KEYS[1]) else return 0 end"
//r.client.Eval(r.ctx, script, []string{r.kvt.key}, r.kvt.value)
script := `if redis.call('hexists',KEYS[1],ARGV[1]) == 0 then return nil
elseif redis.call('hincrby',KEYS[1],ARGV[1],-1) == 0 then return redis.call('del',KEYS[1])
else return 0 end`
r.client.Eval(r.ctx, script, []string{r.kvt.key}, r.kvt.value)
log.Printf("unlock ok: %s,%s,%d\n", r.kvt.key, r.kvt.value, r.kvt.ttl)
}
func (r *RedisLock) autoReNewExpire() {
defer func() {
<-r.lockKeepAliveCh
}()
tc := time.NewTicker(time.Duration(r.kvt.ttl) * time.Second / 3)
defer tc.Stop()
for {
select {
case <-tc.C:
script := `if redis.call('hexists',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2])
else return 0 end`
if r.client.Eval(r.ctx, script, []string{r.kvt.key}, r.kvt.value).Val().(int64) == 0 {
return
}
}
}
}