package main
import (
"context"
"fmt"
"github.com/go-redis/redis"
uuid "github.com/satori/go.uuid"
"strconv"
"time"
)
type RedisLock struct {
//保存连接
rdb *redis.Client
err error
lockValue string
lockName string // 锁名称
ex time.Duration // 锁过期时间
perKeepAlive time.Duration // 续命时间
startKeepAlive time.Duration // 开始续命(小于过期时间)
workerTime int // 模拟任务时间(秒)
}
var redisClient RedisLock
func init() {
redisClient.rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // 指定
Password: "123456",
DB: 0,
})
_, redisClient.err = redisClient.rdb.Ping().Result()
if redisClient.err != nil {
panic(redisClient.err)
}
redisClient.lockName = "redisLock"
redisClient.lockValue = uuid.NewV4().String()
redisClient.ex = 4
redisClient.startKeepAlive = 3
redisClient.perKeepAlive = 4
redisClient.workerTime = 5
}
func main() {
worker()
}
func worker() {
Lock(redisClient.lockName, redisClient.lockValue)
ctx, cancel := context.WithTimeout(context.Background(), redisClient.startKeepAlive*time.Second)
valueTX := context.WithValue(ctx, "KeepAlive", redisClient.perKeepAlive)
go KeepAliveWorker(valueTX)
test()
cancel()
defer UnLock(redisClient.lockName, redisClient.lockValue)
}
//模拟任务超时
func test() {
for i := 1; i <= redisClient.workerTime; i++ {
time.Sleep(time.Second)
fmt.Println(i)
}
}
// 加锁
func Lock(key, lockValue string) (bool, error) {
bool, err := redisClient.rdb.SetNX(key, lockValue, redisClient.ex*time.Second).Result()
if err != nil {
return false, err
}
fmt.Println("上锁成功", "key:", key, "lockValue:", lockValue)
return bool, nil
}
// 解锁
func UnLock(key, s string) bool {
//解锁的脚本
unLockScript := `local lockValue = redis.call("GET", KEYS[1])
if lockValue == ARGV[1] then
-- 执行成功返回“1”
return redis.call("DEL", KEYS[1])
else
return 0
end`
resp, err := redisClient.rdb.Eval(unLockScript, []string{key}, []string{s}).Result()
//fmt.Printf("%T", resp)
fmt.Println("解锁:", resp.(int64) == 1)
if err != nil {
fmt.Println("解锁失败", resp, err)
return false
}
fmt.Println("解锁成功", resp)
return true
}
//续租任务 通过超时和主动取消控制
func KeepAliveWorker(ctx context.Context) {
//维持锁的脚本
KeepAliveScript := `if ( redis.call("GET", KEYS[1]) )
then
redis.call('expire', KEYS[1], ARGV[1])
return "ok"
end
return "fail"`
for {
select {
case <-ctx.Done():
// 执行续租任务
res := redisClient.rdb.Eval(
KeepAliveScript,
[]string{redisClient.lockName},
[]string{strconv.Itoa(int(redisClient.perKeepAlive))})
if res.Err() != nil {
panic(res.Err().Error())
}
if res.Val().(string) == "ok" {
fmt.Println("key:", redisClient.lockName, "续命成功:", redisClient.perKeepAlive)
return
}
fmt.Println("续命失败", res.Val())
return
}
}
}
redis续期 redis续命
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。

提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章