代码拉取完成,页面将自动刷新
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
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。