Documentation
¶
Index ¶
- Variables
- type Lock
- type RedisLocker
- func (r *RedisLocker) ObtainWithRetry(ctx context.Context, key string, ttl time.Duration, maxRetries int, ...) (lock *Lock, ok bool, err error)
- func (r *RedisLocker) ObtainWithTimeout(ctx context.Context, key string, ttl, timeout, backoff time.Duration) (lock *Lock, ok bool, err error)
- func (r *RedisLocker) TryObtain(ctx context.Context, key string, ttl time.Duration) (lock *Lock, ok bool, err error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEmptyKey = errors.New("key must not be empty")
var ErrInvalidBackoff = errors.New("backoff must be positive")
var ErrInvalidMaxRetries = errors.New("maxRetries must not be negative")
var ErrInvalidTTL = errors.New("ttl must be positive")
var ErrInvalidTimeout = errors.New("timeout must be positive")
var ErrLockExpired = errors.New("lock has expired")
var ErrLockNotHeld = errors.New("lock not held")
var ErrLockNotInitialized = errors.New("lock not initialized")
Functions ¶
This section is empty.
Types ¶
type Lock ¶
type Lock struct {
// contains filtered or unexported fields
}
func (*Lock) Refresh ¶
Refresh extends the lock with a new TTL. ttl is the lock's new time-to-live after refresh, must be positive. Returns (true, nil) on success, (false, nil) if the lock is no longer held (expired or released), and an error only on underlying Redis failures. Returns ErrInvalidTTL if ttl <= 0. Returns ErrLockNotInitialized if the Lock was not initialized (programming error).
func (*Lock) Release ¶
Release releases the lock manually. Returns ErrLockNotHeld if the lock is no longer held (expired or released).
func (*Lock) TTL ¶
TTL returns the remaining time to live of the lock. Returns (ttl, nil) with ttl > 0 if the lock is held. Returns (0, ErrLockExpired) if the lock is no longer held (expired, released, or held by someone else). Returns ErrLockNotInitialized if the Lock was not initialized (programming error).
type RedisLocker ¶
type RedisLocker struct {
// contains filtered or unexported fields
}
RedisLocker redis locker
func NewRedisLocker ¶
func NewRedisLocker(client redislock.RedisClient) (*RedisLocker, error)
NewRedisLocker creates a RedisLocker with the given redis client. Returns an error if client is nil.
func (*RedisLocker) ObtainWithRetry ¶
func (r *RedisLocker) ObtainWithRetry(ctx context.Context, key string, ttl time.Duration, maxRetries int, backoff time.Duration) (lock *Lock, ok bool, err error)
ObtainWithRetry attempts to obtain the lock with a limited number of retry attempts (count-based control). ttl is the lock's time-to-live after being obtained, NOT the acquire timeout. maxRetries is the number of retries (excluding the first attempt), so total attempts = maxRetries + 1. backoff is the duration between retry attempts, must be positive.
Returns (lock, true, nil) on success, (nil, false, nil) if the lock could not be obtained after all retries, and an error only on underlying Redis failures. Returns ErrInvalidTTL if ttl <= 0. Returns ErrInvalidMaxRetries if maxRetries < 0. Returns ErrInvalidBackoff if backoff <= 0. Returns ErrEmptyKey if key is empty.
example: Retry every 100ms, for up-to 3x ObtainWithRetry(context.Background(), "key", time.Second, 3, 100 * time.Millisecond)
Example ¶
lock, ok, err := locker.ObtainWithRetry(
context.Background(),
"redis:key",
time.Second*10,
5,
time.Second,
)
if err != nil {
// redis operation error
log.Fatal(err)
}
if !ok {
// lock not obtained
log.Fatal("lock not obtained")
}
// release lock
_ = lock.Release(context.Background())
func (*RedisLocker) ObtainWithTimeout ¶
func (r *RedisLocker) ObtainWithTimeout(ctx context.Context, key string, ttl, timeout, backoff time.Duration) (lock *Lock, ok bool, err error)
ObtainWithTimeout attempts to obtain the lock with a total timeout, retrying every backoff until timeout expires (time-based control). ttl is the lock's time-to-live after being obtained, NOT the acquire timeout. timeout is the maximum total time to spend acquiring the lock. backoff is the duration between retry attempts.
Returns (lock, true, nil) on success, (nil, false, nil) if the lock could not be obtained within timeout, and an error only on underlying Redis failures. Returns ErrInvalidTTL if ttl <= 0. Returns ErrInvalidTimeout if timeout <= 0. Returns ErrInvalidBackoff if backoff <= 0. Returns ErrEmptyKey if key is empty.
example: ttl is 1s, Retry every 500ms, for up-to a minute ObtainWithTimeout(context.Background(), "key", time.Second, time.Minute, 500 * time.Millisecond)
Example ¶
lock, ok, err := locker.ObtainWithTimeout(
context.Background(),
"redis:key",
time.Second*5,
time.Second,
time.Millisecond*500,
)
if err != nil {
// redis operation error
log.Fatal(err)
}
if !ok {
// lock not obtained
log.Fatal("lock not obtained")
}
// release lock
_ = lock.Release(context.Background())
func (*RedisLocker) TryObtain ¶
func (r *RedisLocker) TryObtain(ctx context.Context, key string, ttl time.Duration) (lock *Lock, ok bool, err error)
TryObtain attempts to obtain the lock a single time without retry. ttl is the lock's time-to-live after being obtained, NOT the acquire timeout. Returns (lock, true, nil) on success, (nil, false, nil) if the lock is already held by someone else, and an error only on underlying Redis failures. Returns ErrInvalidTTL if ttl <= 0. Returns ErrEmptyKey if key is empty.
Example ¶
client := redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
var err error
locker, err = NewRedisLocker(client)
if err != nil {
log.Fatal(err)
}
lock, ok, err := locker.TryObtain(context.Background(), "redis:key", time.Millisecond*500)
if err != nil {
// redis operation error
log.Fatal(err)
}
if !ok {
// lock not obtained
log.Fatal("lock not obtained")
}
// release lock
_ = lock.Release(context.Background())
// return remaining TTL
_, _ = lock.TTL(context.Background())