48 lines
1.1 KiB
Go
48 lines
1.1 KiB
Go
package redislock
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
|
)
|
|
|
|
// Lock is a small Redis lease. Value must uniquely identify the worker that
|
|
// owns it; Release uses a Lua compare-and-delete to avoid deleting a renewed
|
|
// lease owned by another worker.
|
|
type Lock struct {
|
|
client *redis.Redis
|
|
key string
|
|
owner string
|
|
ttl time.Duration
|
|
}
|
|
|
|
func New(conf redis.RedisConf, key, owner string, ttl time.Duration) *Lock {
|
|
return &Lock{client: redis.MustNewRedis(conf), key: key, owner: owner, ttl: ttl}
|
|
}
|
|
|
|
func (l *Lock) Acquire(ctx context.Context) (bool, error) {
|
|
if l == nil || l.client == nil || l.key == "" || l.owner == "" {
|
|
return false, fmt.Errorf("invalid redis lock")
|
|
}
|
|
seconds := int(l.ttl.Seconds())
|
|
if seconds < 1 {
|
|
seconds = 1
|
|
}
|
|
return l.client.SetnxExCtx(ctx, l.key, l.owner, seconds)
|
|
}
|
|
|
|
func (l *Lock) Release(ctx context.Context) error {
|
|
if l == nil || l.client == nil {
|
|
return fmt.Errorf("invalid redis lock")
|
|
}
|
|
_, err := l.client.EvalCtx(ctx, `
|
|
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
|
return redis.call('DEL', KEYS[1])
|
|
end
|
|
return 0
|
|
`, []string{l.key}, l.owner)
|
|
return err
|
|
}
|