59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package lock
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/XingfenD/yoresee_doc/pkg/errs"
|
|
"github.com/XingfenD/yoresee_doc/pkg/storage"
|
|
)
|
|
|
|
// distributed lock, depredated by usage of singleflight
|
|
type DistributedLock struct {
|
|
key string
|
|
value string
|
|
expiration time.Duration
|
|
}
|
|
|
|
func NewDistributedLock(key string, expiration time.Duration) *DistributedLock {
|
|
return &DistributedLock{
|
|
key: key,
|
|
value: fmt.Sprintf("%d", time.Now().UnixNano()),
|
|
expiration: expiration,
|
|
}
|
|
}
|
|
|
|
func (dl *DistributedLock) Lock(ctx context.Context) error {
|
|
success, err := storage.SetNX(ctx, dl.key, dl.value, dl.expiration)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !success {
|
|
return errs.Detail(errs.ErrLockAcquireFailed, dl.key)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (dl *DistributedLock) TryLock(ctx context.Context) (bool, error) {
|
|
return storage.SetNX(ctx, dl.key, dl.value, dl.expiration)
|
|
}
|
|
|
|
func (dl *DistributedLock) Unlock(ctx context.Context) error {
|
|
script := `
|
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
return redis.call("del", KEYS[1])
|
|
else
|
|
return 0
|
|
end
|
|
`
|
|
result, err := storage.GetRedis().Eval(ctx, script, []string{dl.key}, dl.value).Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.(int64) == 0 {
|
|
return errs.Detail(errs.ErrLockNotHeld, dl.key)
|
|
}
|
|
return nil
|
|
}
|