redislock

package module
v1.6.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Redis Distributed Lock Plugin for Lynx Framework

The Redis Distributed Lock Plugin provides a robust, high-performance distributed locking mechanism for the Lynx framework using Redis as the coordination backend. It supports automatic renewal, retry mechanisms, reentrancy (same instance), and works with standalone, Cluster, and Sentinel via redis.UniversalClient.

Design and limitations: See LIMITATIONS.md for single-node vs Redlock, process pause/TTL, fencing token usage, renewal failure behavior, and shutdown/script timeout.

Features

Core Locking Capabilities
  • Distributed Locking: Redis-based distributed lock implementation
  • Automatic Renewal: Configurable automatic lock renewal to prevent expiration
  • Retry Mechanisms: Intelligent retry logic with exponential backoff
  • Lock Timeout: Configurable lock expiration and timeout handling
Advanced Features
  • Reentrant Locks: Reentrancy by reusing the same *RedisLock instance (multiple Acquire/Release on one instance)
  • Lock Monitoring: Real-time lock status monitoring and statistics
  • Graceful Shutdown: Proper cleanup and resource management
  • Performance Optimization: High-performance lock operations with minimal overhead
  • Error Handling: Comprehensive error handling and recovery mechanisms
Monitoring & Observability
  • Prometheus Metrics: Comprehensive monitoring and alerting
  • Performance Analytics: Lock acquisition and release performance metrics
  • Error Tracking: Detailed error categorization and reporting
  • Statistics Collection: Renewal manager and lock usage statistics

Architecture

The plugin follows the Lynx framework's layered architecture:

┌─────────────────────────────────────────────────────────────┐
│                    Application Layer                        │
├─────────────────────────────────────────────────────────────┤
│                    Lock Plugin Layer                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │   Client    │  │   Manager   │  │   Configuration    │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│                    Lock Management Layer                    │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │   Lock      │  │   Renewal   │  │   Retry Logic      │ │
│  │   Instance  │  │   Service   │  │     Handler        │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│                    Redis Layer                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │   Lua       │  │   Redis     │  │   Connection       │ │
│  │   Scripts   │  │   Client    │  │     Pool           │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Configuration

Runtime Prerequisites

This module does not define a standalone lynx.redis.lock or lynx.redis.lock.* config section. It obtains the underlying Redis client from github.com/go-lynx/lynx-redis via GetUniversalRedis(), so configure topology, authentication, TLS, and pool settings in the Redis plugin first.

lynx:
  redis:
    addrs: ["localhost:6379"]
    password: ""
    db: 0

For Cluster or Sentinel examples, see ../lynx-redis/README.md and ../lynx-redis/conf/example_config.yml.

Lock Behavior Configuration

Lock expiration, retry, renewal, worker-pool size, and script timeouts are configured in code through LockOptions, not through YAML.

options := redislock.DefaultLockOptions
options.Expiration = 30 * time.Second
options.RetryStrategy = redislock.RetryStrategy{
    MaxRetries: 3,
    RetryDelay: 100 * time.Millisecond,
}
options.RenewalEnabled = true
options.RenewalThreshold = 0.3
options.WorkerPoolSize = 50
options.RenewalConfig = redislock.RenewalConfig{
    MaxRetries:    4,
    BaseDelay:     100 * time.Millisecond,
    MaxDelay:      800 * time.Millisecond,
    CheckInterval: 300 * time.Millisecond,
    CallTimeout:   600 * time.Millisecond,
}
options.ScriptCallTimeout = 600 * time.Millisecond

Usage

Basic Usage
package main

import (
    "context"
    "fmt"
    "log"
    "time"
    redislock "github.com/go-lynx/lynx-redis-lock"
)

func main() {
    // Requires the lynx-redis plugin to be initialized first.
    err := redislock.Lock(context.Background(), "my-lock", 30*time.Second, func() error {
        // Critical section - your business logic here
        fmt.Println("Executing critical section")
        time.Sleep(5 * time.Second)
        return nil
    })

    if err != nil {
        log.Printf("Failed to acquire lock: %v", err)
    }
}
Advanced Usage with Options
// Configure lock options
options := redislock.LockOptions{
    Expiration:       60 * time.Second,
    RetryStrategy:    redislock.RetryStrategy{MaxRetries: 3, RetryDelay: 100 * time.Millisecond},
    RenewalEnabled:   true,
    RenewalThreshold: 0.5,
}

err := redislock.LockWithOptions(context.Background(), "my-lock", options, func() error {
    // Long-running critical section
    fmt.Println("Executing long-running critical section")
    time.Sleep(30 * time.Second)
    return nil
})
Manual Lock Management
// Create a reusable lock instance and acquire it (works with standalone/Cluster/Sentinel via GetUniversalRedis)
options := redislock.LockOptions{Expiration: 30 * time.Second}
lock, err := redislock.NewLock(ctx, "my-lock", options)
if err != nil {
    return err
}
if err := lock.Acquire(ctx); err != nil {
    return err
}
defer lock.Release(ctx)

// Check if current instance holds the lock
held, err := lock.IsLocked(ctx)
if err == nil && held {
    fmt.Println("Lock is held")
}

// Optional: manual renewal
_ = lock.Renew(ctx, 30*time.Second)
Reentrant Locks

Reentrancy is per lock instance: use one *RedisLock and call Acquire multiple times (and the same number of Release). Each new Lock() or NewLock() creates a different instance and different holder identity, so they do not reenter.

options := redislock.LockOptions{Expiration: 30 * time.Second}
lock, _ := redislock.NewLock(ctx, "my-lock", options)
_ = lock.Acquire(ctx)
defer lock.Release(ctx)
// Reenter with the same instance
_ = lock.Acquire(ctx)
defer lock.Release(ctx)
// Critical section

Or use LockWithToken and inside the callback use the same lock for nested work if you need the fencing token in the callback.

API Reference

Core Functions
  • Lock(ctx, key, expiration, fn) error - Acquire lock and execute function (uses default options).
  • LockWithOptions(ctx, key, options, fn) error - Acquire lock with full options.
  • LockWithRetry(ctx, key, expiration, fn, strategy) error - Acquire with custom retry strategy.
  • LockWithToken(ctx, key, expiration, fn func(token int64) error) error - Acquire and run callback with fencing token (see LIMITATIONS.md).
  • NewLock(ctx, key, options) (*RedisLock, error) - Create a reusable lock instance (then call Acquire/Release); reentrancy is per instance.
  • UnlockByValue(ctx, key, value) error - Release by key and value (e.g. from another process that stored the value).
Lock Instance Methods
  • Acquire(ctx) error - Acquire or reenter (same instance).
  • AcquireWithRetry(ctx, strategy) error - Acquire with retries.
  • Release(ctx) error - Release (or partial release when reentrant).
  • Renew(ctx, newExpiration) error - Manually extend TTL.
  • IsLocked(ctx) (bool, error) - Whether the current instance holds the lock.
  • GetKey() string, GetExpiration() time.Duration, GetExpiresAt() time.Time, GetToken() int64 - Status accessors.
Configuration Options
type LockOptions struct {
    Expiration       time.Duration
    RetryStrategy     RetryStrategy  // MaxRetries, RetryDelay
    RenewalEnabled     bool
    RenewalThreshold   float64
    WorkerPoolSize     int
    RenewalConfig      RenewalConfig
    ScriptCallTimeout  time.Duration
}

Monitoring and Metrics

Statistics
stats := redislock.GetStats()
// total_locks, active_locks, renewal_count, renewal_errors, skipped_renewals, etc.
log.Printf("Active locks: %d, Renewal count: %d", stats["active_locks"], stats["renewal_count"])
Graceful shutdown
// Stop renewal service and wait for active locks to drop to zero (or timeout)
if err := redislock.Shutdown(ctx); err != nil {
    log.Printf("Shutdown: %v", err)
}

See LIMITATIONS.md for shutdown semantics (no forced release in Redis).

Prometheus Metrics

Register with redislock.InitMetrics(reg). Exposed metrics (namespace lynx, subsystem redis_lock):

Metric Type Labels / Description
lynx_redis_lock_acquire_total Counter result (success, conflict, error)
lynx_redis_lock_unlock_total Counter result (full, partial, not_held, error)
lynx_redis_lock_renew_total Counter result (success, not_owner, not_exist, fail, error)
lynx_redis_lock_skipped_renewals_total Counter Renew tasks skipped (worker pool full)
lynx_redis_lock_active_locks Gauge Current locks in the renewal manager
lynx_redis_lock_script_latency_seconds Histogram op (acquire, unlock, renew)

Validation

Current automated baseline in this workspace is go test ./... -> [no test files]. See VALIDATION.md for the exact output and the recommended manual smoke checks.

Performance Tuning

Lock Option Tuning
options := redislock.DefaultLockOptions
options.Expiration = 10 * time.Second
options.RetryStrategy = redislock.RetryStrategy{
    MaxRetries: 5,
    RetryDelay: 50 * time.Millisecond,
}
options.RenewalThreshold = 0.3
options.WorkerPoolSize = 100
options.RenewalConfig.CheckInterval = 200 * time.Millisecond
Redis Configuration

Tune connection pool, retry, TLS, and Sentinel/Cluster topology in lynx-redis; this package reuses that redis.UniversalClient instead of owning a second configuration surface.

Troubleshooting

Common Issues
  1. Lock Acquisition Failures

    • Check Redis connectivity
    • Verify lock key uniqueness
    • Review timeout settings
  2. Lock Not Releasing

    • Check for panic in critical section
    • Verify proper error handling
    • Monitor lock expiration
  3. Performance Issues

    • Optimize lock timeout settings
    • Review retry configuration
    • Monitor Redis performance
  4. Deadlock Issues

    • Use consistent lock ordering
    • Implement lock timeouts
    • Monitor lock statistics
Debug Mode

There is no dedicated lynx.redis.lock.logging config block. For troubleshooting, use application-level logging, redislock.GetStats(), Prometheus collectors from redislock.InitMetrics, and redislock.SetCallback(...) if you need to observe acquire/release/renew events.

Best Practices

Lock Design
  • Use descriptive lock keys
  • Keep critical sections short
  • Implement proper error handling
  • Use appropriate timeouts
Performance
  • Optimize lock duration
  • Use connection pooling
  • Monitor lock statistics
  • Tune WorkerPoolSize, ScriptCallTimeout, and renewal intervals to match Redis latency
Reliability
  • Handle lock failures gracefully
  • Implement retry logic
  • Use lock renewal for long operations
  • Monitor renewal errors and skipped renewals
Security
  • Use secure Redis connections
  • Implement proper authentication
  • Validate lock keys
  • Monitor lock usage

Dependencies

  • github.com/redis/go-redis/v9 - Redis client (lock uses UniversalClient for standalone/cluster/sentinel)
  • github.com/go-lynx/lynx - Lynx framework core
  • github.com/go-lynx/lynx-redis - Redis plugin (provides GetUniversalRedis())
  • github.com/prometheus/client_golang - Prometheus metrics

License

This plugin is part of the Lynx framework and follows the same license terms.

Contributing

Contributions are welcome! Please see the main Lynx framework contribution guidelines.

Support

For support and questions:

Documentation

Overview

Package redislock provides a Redis-based distributed lock for the Lynx framework.

It supports standalone, Cluster, and Sentinel via redis.UniversalClient. Features include: atomic acquire/release/renew via Lua scripts, reentrancy per lock instance, optional auto-renewal, retry with jitter, and fencing token (see LockWithToken). For design limits (single-node vs Redlock, process pause, renewal failure), see LIMITATIONS.md.

Index

Constants

View Source
const (
	ErrCodeLockNotHeld           = "LOCK_NOT_HELD"
	ErrCodeLockAcquireFailed     = "LOCK_ACQUIRE_FAILED"
	ErrCodeLockAcquireTimeout    = "LOCK_ACQUIRE_TIMEOUT"
	ErrCodeLockAcquireConflict   = "LOCK_ACQUIRE_CONFLICT"
	ErrCodeRedisClientNotFound   = "REDIS_CLIENT_NOT_FOUND"
	ErrCodeMaxRetriesExceeded    = "MAX_RETRIES_EXCEEDED"
	ErrCodeLockFnRequired        = "LOCK_FN_REQUIRED"
	ErrCodeLockRenewalFailed     = "LOCK_RENEWAL_FAILED"
	ErrCodeRenewalServiceStopped = "RENEWAL_SERVICE_STOPPED"
	ErrCodeInvalidOptions        = "INVALID_OPTIONS"
)

Error code definitions

View Source
const MaxLockKeyLength = 255

MaxLockKeyLength is the maximum allowed length for a lock key (business key, not the internal Redis key).

Variables

View Source
var (
	// ErrLockNotHeld indicates attempting to release a lock not held
	ErrLockNotHeld = newLockError(ErrCodeLockNotHeld, "lock not held", nil)
	// ErrLockAcquireFailed indicates lock acquisition failure
	ErrLockAcquireFailed = newLockError(ErrCodeLockAcquireFailed, "failed to acquire lock", nil)
	// ErrLockAcquireTimeout indicates lock acquisition timeout
	ErrLockAcquireTimeout = newLockError(ErrCodeLockAcquireTimeout, "lock acquire timeout", nil)
	// ErrLockAcquireConflict indicates lock acquisition conflict
	ErrLockAcquireConflict = newLockError(ErrCodeLockAcquireConflict, "lock acquire conflict", nil)
	// ErrRedisClientNotFound indicates Redis client not found
	ErrRedisClientNotFound = newLockError(ErrCodeRedisClientNotFound, "redis client not found", nil)
	// ErrMaxRetriesExceeded indicates exceeding maximum retry attempts
	ErrMaxRetriesExceeded = newLockError(ErrCodeMaxRetriesExceeded, "max retries exceeded", nil)
	// ErrLockFnRequired indicates lock protected function cannot be empty
	ErrLockFnRequired = newLockError(ErrCodeLockFnRequired, "lock function is required", nil)
	// ErrLockRenewalFailed indicates lock renewal failure
	ErrLockRenewalFailed = newLockError(ErrCodeLockRenewalFailed, "lock renewal failed", nil)
	// ErrRenewalServiceStopped indicates renewal service has stopped
	ErrRenewalServiceStopped = newLockError(ErrCodeRenewalServiceStopped, "renewal service stopped", nil)
	// ErrInvalidOptions indicates invalid configuration options
	ErrInvalidOptions = newLockError(ErrCodeInvalidOptions, "invalid options", nil)
)
View Source
var (
	DefaultRetryStrategy = RetryStrategy{
		MaxRetries: 3,
		RetryDelay: 100 * time.Millisecond,
	}

	DefaultRenewalConfig = RenewalConfig{

		MaxRetries:    4,
		BaseDelay:     100 * time.Millisecond,
		MaxDelay:      800 * time.Millisecond,
		CheckInterval: 300 * time.Millisecond,
		CallTimeout:   600 * time.Millisecond,
	}

	DefaultLockOptions LockOptions
)

Default configurations

Functions

func GetErrorMessage

func GetErrorMessage(code, lang string) string

GetErrorMessage gets internationalized error message

func GetStats

func GetStats() map[string]int64

GetStats gets lock manager statistics

func InitMetrics

func InitMetrics(reg prometheus.Registerer)

InitMetrics registers the collectors to the provided Registerer. Pass nil to use the default Registerer.

func IsLockError

func IsLockError(err error, code string) bool

Error checking helper function

func Lock

func Lock(ctx context.Context, key string, expiration time.Duration, fn func() error) error

Lock acquires a distributed lock for the specified key and executes the callback function, automatically releasing the lock after execution. - Uses DefaultLockOptions as base configuration, only overriding Expiration. - Uses Lua script for atomic lock acquisition/reentrancy, avoiding race conditions. - If renewal is enabled, registers in global manager and automatically renews until function execution ends.

func LockWithOptions

func LockWithOptions(ctx context.Context, key string, options LockOptions, fn func() error) (retErr error)

LockWithOptions uses complete configuration options to acquire lock and execute callback function. Key behaviors:

  • Delegates acquisition and retry to lock.AcquireWithRetry, which calls Acquire once per attempt.
  • After successful acquisition, if renewal is enabled, register in global manager and start renewal service.
  • Release is performed via defer on an independent short-timeout context so a cancelled business ctx cannot block best-effort release. Release.go already calls removeManagedLock on full release, so no extra IsLocked round-trip is needed.

Errors:

  • Acquisition failures due to contention trigger OnLockAcquireFailed callback inside Acquire and are subject to the retry strategy; other errors are returned immediately.

func LockWithRetry

func LockWithRetry(ctx context.Context, key string, expiration time.Duration, fn func() error, strategy RetryStrategy) error

LockWithRetry acquires lock and executes function, supports retry by strategy. - Based on DefaultLockOptions, overrides Expiration and RetryStrategy, others use defaults. - Uses random jitter (0.5~1.5x) during retries to reduce hot spot collisions.

func LockWithToken

func LockWithToken(ctx context.Context, key string, expiration time.Duration, fn func(token int64) error) (retErr error)

LockWithToken acquires a distributed lock and runs fn; the callback receives a fencing token (see LIMITATIONS.md). - Based on DefaultLockOptions, only overriding Expiration, retry strategy uses DefaultRetryStrategy. - token is only incremented on "first acquisition" (non-reentrant); reentry does not generate a new token.

func SetCallback

func SetCallback(callback LockCallback)

SetCallback installs the process-wide lock-event callback; nil resets to no-op.

func Shutdown

func Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the lock manager. It stops the renewal service and polls until all active locks are released or the context is cancelled. Callers control the deadline via ctx — e.g.:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_ = redislock.Shutdown(ctx)

func UnlockByValue

func UnlockByValue(ctx context.Context, key, value string) error

UnlockByValue releases lock using key + value method (no need to hold RedisLock instance). Semantic explanation:

  • When count > 0, this operation is a "partial release". This implementation uniformly passes TTL=0 to the script, indicating not to refresh TTL (keeping the remaining expiration time unchanged).
  • When key does not exist or value does not match, returns ErrLockNotHeld.

Timeout explanation: - Single script call uses DefaultLockOptions.ScriptCallTimeout as optional per-call timeout.

func ValidateKey

func ValidateKey(key string) error

ValidateKey validates the lock key: non-empty, length <= MaxLockKeyLength, printable ASCII, no '{' or '}'.

Types

type LockCallback

type LockCallback interface {
	OnLockAcquired(key string, duration time.Duration)
	OnLockReleased(key string, duration time.Duration)
	OnLockRenewed(key string, duration time.Duration)
	OnLockRenewalFailed(key string, error error)
	OnLockAcquireFailed(key string, error error)
}

LockCallback lock operation callback interface

type LockError

type LockError struct {
	Code    string
	Message string
	Err     error
}

LockError custom lock error type

func (*LockError) Error

func (e *LockError) Error() string

func (*LockError) Unwrap

func (e *LockError) Unwrap() error

type LockOptions

type LockOptions struct {
	Expiration       time.Duration // Lock expiration time
	RetryStrategy    RetryStrategy // Retry strategy
	RenewalEnabled   bool          // Whether to enable auto renewal
	RenewalThreshold float64       // Renewal threshold (proportion relative to expiration time, default 1/3)
	WorkerPoolSize   int           // Renewal worker pool size, default 50
	RenewalConfig    RenewalConfig // Renewal configuration
	// ScriptCallTimeout timeout control for single script call (acquire/release). 0 means no separate timeout.
	ScriptCallTimeout time.Duration
	// TokenTTL is the TTL applied to the fencing-token counter key in Redis.
	// The counter must outlive individual lock sessions to keep tokens monotonically increasing.
	// Defaults to 7 days. Set to 0 to use the default.
	TokenTTL time.Duration
}

LockOptions configures lock behavior: expiration, retry, renewal, and script timeouts.

func (*LockOptions) Validate

func (lo *LockOptions) Validate() error

Validate validates the lock options (expiration, renewal threshold, worker pool size, retry strategy).

type NoOpCallback

type NoOpCallback struct{}

NoOpCallback empty implementation callback

func (NoOpCallback) OnLockAcquireFailed

func (NoOpCallback) OnLockAcquireFailed(key string, error error)

func (NoOpCallback) OnLockAcquired

func (NoOpCallback) OnLockAcquired(key string, duration time.Duration)

func (NoOpCallback) OnLockReleased

func (NoOpCallback) OnLockReleased(key string, duration time.Duration)

func (NoOpCallback) OnLockRenewalFailed

func (NoOpCallback) OnLockRenewalFailed(key string, error error)

func (NoOpCallback) OnLockRenewed

func (NoOpCallback) OnLockRenewed(key string, duration time.Duration)

type Provider added in v1.6.1

type Provider interface {
	NewLock(ctx context.Context, key string, options LockOptions) (*RedisLock, error)
	Lock(ctx context.Context, key string, expiration time.Duration, fn func() error) error
	LockWithOptions(ctx context.Context, key string, options LockOptions, fn func() error) error
	LockWithToken(ctx context.Context, key string, expiration time.Duration, fn func(token int64) error) error
	UnlockByValue(ctx context.Context, key, value string) error
}

Provider exposes redis-lock through an injectable facade while resolving the underlying Redis client via lynx-redis's stable provider on each call.

func GetProvider added in v1.6.1

func GetProvider() Provider

GetProvider returns the injectable redis lock facade.

type RedisLock

type RedisLock struct {
	// contains filtered or unexported fields
}

RedisLock implements Redis-based distributed lock. provider resolves the current UniversalClient on demand so long-lived lock handles do not cache a replaceable Redis client across reconnects or managed restarts.

func NewLock

func NewLock(ctx context.Context, key string, options LockOptions) (*RedisLock, error)

NewLock creates a reusable lock instance (supports reentrancy within the same instance). Behavior: - Does not actively trigger locking, only builds RedisLock object; caller must explicitly call Acquire() to obtain or reenter lock. - Multiple Acquire calls on the same instance are treated as reentrant by the script due to unchanged value, and TTL is refreshed. - Redis Cluster: internal ownerKey and countKey use the same hashtag to ensure same slot for Lua atomic operations.

func (*RedisLock) Acquire

func (rl *RedisLock) Acquire(ctx context.Context) error

Acquire attempts to acquire (or reenter) the lock based on the current RedisLock instance. If called again on the same instance, the Lua script treats it as reentrant and renews the TTL because the value remains unchanged. The fencing token is incremented atomically inside the script on first acquisition; no separate Redis round-trip is needed.

func (*RedisLock) AcquireWithRetry

func (rl *RedisLock) AcquireWithRetry(ctx context.Context, strategy RetryStrategy) error

AcquireWithRetry acquires (or reenters) the lock and retries according to strategy

func (*RedisLock) EnableAutoRenew

func (rl *RedisLock) EnableAutoRenew(options LockOptions)

EnableAutoRenew registers the current lock to the global renewal manager (starts if not already started)

func (*RedisLock) GetAcquiredAt

func (rl *RedisLock) GetAcquiredAt() time.Time

GetAcquiredAt returns when the lock was acquired (guarded by mutex for consistency with renewal).

func (*RedisLock) GetExpiration

func (rl *RedisLock) GetExpiration() time.Duration

GetExpiration returns the configured lock TTL.

func (*RedisLock) GetExpiresAt

func (rl *RedisLock) GetExpiresAt() time.Time

GetExpiresAt returns the absolute expiration time (guarded by mutex).

func (*RedisLock) GetKey

func (rl *RedisLock) GetKey() string

GetKey returns the business lock key (as passed to NewLock / Lock).

func (*RedisLock) GetRemainingTime

func (rl *RedisLock) GetRemainingTime() time.Duration

GetRemainingTime returns the remaining TTL until expiry (guarded by mutex).

func (*RedisLock) GetStatus

func (rl *RedisLock) GetStatus() (remainingTime time.Duration, isExpired bool)

GetStatus returns remaining TTL and whether the lock is already expired (single snapshot under mutex).

func (*RedisLock) GetToken

func (rl *RedisLock) GetToken() int64

GetToken returns the most recently acquired fencing token (generated on non-reentrant acquisition). If 0, the lock has not been acquired for the first time in this process (or only reentry occurred). Fencing semantics: the resource layer must reject requests with an older token. See LIMITATIONS.md.

func (*RedisLock) IsExpired

func (rl *RedisLock) IsExpired() bool

IsExpired reports whether the lock’s local expiry time has passed (guarded by mutex).

func (*RedisLock) IsLocked

func (rl *RedisLock) IsLocked(ctx context.Context) (bool, error)

IsLocked returns whether the current instance holds the lock in Redis (by value match).

func (*RedisLock) Release

func (rl *RedisLock) Release(ctx context.Context) error

Release releases the lock (or one reentry count); returns ErrLockNotHeld if not owner or already released.

func (*RedisLock) Renew

func (rl *RedisLock) Renew(ctx context.Context, newExpiration time.Duration) error

Renew extends the lock TTL in Redis to newExpiration; caller must hold the lock.

type RenewalConfig

type RenewalConfig struct {
	MaxRetries    int           // Maximum renewal retry attempts
	BaseDelay     time.Duration // Base retry delay
	MaxDelay      time.Duration // Maximum retry delay
	CheckInterval time.Duration // Renewal check interval
	// CallTimeout single renewal script call timeout. 0 means no separate timeout.
	CallTimeout time.Duration
}

RenewalConfig renewal configuration

type RetryStrategy

type RetryStrategy struct {
	MaxRetries int           // Maximum retry attempts
	RetryDelay time.Duration // Retry interval
}

RetryStrategy defines lock retry strategy

func (*RetryStrategy) Validate

func (rs *RetryStrategy) Validate() error

Validate validates the retry strategy (MaxRetries and RetryDelay non-negative).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL