Files
2026-07-15 22:42:31 +08:00

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
}