Documentation
¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( ErrFailedToPreemptLock = errors.New("failed to preempt lock") ErrLockNotHeld = errors.New("lock not held") )
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
type FixedIntervalRetryStrategy ¶
type FixedIntervalRetryStrategy struct {
Interval time.Duration
MaxCnt int
// contains filtered or unexported fields
}
FixedIntervalRetryStrategy 固定间隔重试
type Lock ¶
type Lock struct {
// contains filtered or unexported fields
}
func (*Lock) AutoRefresh ¶
AutoRefresh 不建议使用这个API,用户最好是自己手动控制Refresh interval 多久续约一次 timeout 调用续约的超时时间
Example ¶
// 抢到了锁
var l *Lock
go func() {
_ = l.AutoRefresh(time.Millisecond, time.Second*3)
// 处理错误,需要中断业务
}()
// 执行业务
fmt.Println("Hello")
Output: Hello
func (*Lock) Refresh ¶
Refresh 用户手动续约
Example ¶
// 假设加锁成功,拿到了lock
var l *Lock
// 业务执行完毕的信号
stopChan := make(chan struct{})
// 续约失败的信号
errChan := make(chan error)
done := false
go func() {
timeoutChan := make(chan struct{}, 1)
ticker := time.NewTicker(time.Second * 10)
defer ticker.Stop()
for !done {
select {
case <-stopChan:
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
_ = l.Unlock(ctx)
cancel()
done = true
case <-ticker.C:
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
err := l.Refresh(ctx)
cancel()
switch {
// 处理error
case errors.Is(err, context.DeadlineExceeded):
// 自己给自己发信号,channel一定要带缓存的
timeoutChan <- struct{}{}
continue
case err == nil:
default:
errChan <- err
_ = l.Unlock(ctx)
done = true
}
case <-timeoutChan:
// 尝试一次重试
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
err := l.Refresh(ctx)
cancel()
if err == nil {
// 重试成功
continue
}
errChan <- err
_ = l.Unlock(ctx)
done = true
}
}
}()
// 你的业务
// 业务方在执行时,要在中间步骤检测errChan有没有信号
// 如果续约失败了,业务方需要中断正在处理的业务
// 如果业务在循环中执行
FOR:
for i := 0; i < 100; i++ {
select {
case <-errChan:
// 中断业务
break FOR
default:
// 正常的业务处理
}
}
// 如果你的业务是在多个步骤中执行
select {
case <-errChan:
// 中断业务
default:
// 步骤一
}
select {
case <-errChan:
// 中断业务
default:
// 步骤二
}
select {
case <-errChan:
// 中断业务
default:
// 步骤n
}
// 使用context进行传递中断信号
ctx, cancel := context.WithCancel(context.Background())
// 防止正常结束了业务,但是没人发送ctx取消信号而导致goroutine泄露
defer cancel()
go func() {
for {
select {
case <-errChan:
cancel()
continue
case <-ctx.Done():
// 这一个是为了防止goroutine泄露
return
}
}
}()
// 使用ctx往下传递,下游在执行前需要先判断一下ctx有没有被cancel()
// Next(ctx)
// 业务退出就要退出续约循环
// 不管是被中断了还是正常结束,都需要发送这个信号
stopChan <- struct{}{}
close(stopChan)
close(errChan)
fmt.Println("Hello")
Output: Hello
type RetryStrategy ¶
Click to show internal directories.
Click to hide internal directories.