1 Star 1 Fork 0

kai / 分布式锁

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
lock.go 2.03 KB
一键复制 编辑 原始数据 按行查看 历史
kai 提交于 2023-07-20 17:01 . 增加重试加锁
package ggglock
import (
"context"
"errors"
"github.com/redis/go-redis/v9"
"sync"
"time"
)
type Lock struct {
client redis.Cmdable
key string
value string
//刷新过期时间
expire time.Duration
//解锁信号
unLockChan chan struct{}
//控制不能重复解锁
unlockOnce sync.Once
}
// UnLock 解锁
func (l *Lock) UnLock(ctx context.Context) error {
val, err := l.client.Eval(ctx, luaUnlock, []string{l.key}, l.value).Int64()
//发送解锁信号
defer func() {
l.unlockOnce.Do(func() {
l.unLockChan <- struct{}{}
close(l.unLockChan)
})
}()
if err != nil {
return err
}
if val != 1 {
return ErrNotLock
}
return nil
}
// Refresh 续约
func (l *Lock) Refresh(ctx context.Context) error {
val, err := l.client.Eval(ctx, luaRefresh, []string{l.key}, l.value, l.expire.Seconds()).Int64()
if err != nil {
return err
}
if val != 1 {
return ErrNotLock
}
return nil
}
// AutoRefresh 自动续约
// interval 间隔多长时间续约
// timeOut 超时时间
func (l *Lock) AutoRefresh(interval time.Duration, timeOut time.Duration) error {
//定时
ticker := time.NewTicker(interval)
//超时信号
timeoutChan := make(chan struct{}, 1)
//释放资源
defer func() {
ticker.Stop()
close(timeoutChan)
}()
for {
select {
//定时续约
case <-ticker.C:
ctx, cancel := context.WithTimeout(context.Background(), timeOut)
err := l.Refresh(ctx)
cancel()
//超时给timeoutChan发信号,进入重试分支
if errors.Is(err, context.DeadlineExceeded) {
timeoutChan <- struct{}{}
continue
}
//其他错误直接退出
if err != nil {
return err
}
//超时重试
case <-timeoutChan:
ctx, cancel := context.WithTimeout(context.Background(), timeOut)
err := l.Refresh(ctx)
cancel()
//超时给timeoutChan发信号,进入重试分支
if errors.Is(err, context.DeadlineExceeded) {
timeoutChan <- struct{}{}
continue
}
//其他错误直接退出
if err != nil {
return err
}
//主动解锁
case <-l.unLockChan:
return nil
}
}
}
Go
1
https://gitee.com/youbadbadcom/ggglock.git
git@gitee.com:youbadbadcom/ggglock.git
youbadbadcom
ggglock
分布式锁
v0.0.5

搜索帮助