### Install Redsync Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Installs the Redsync library and its dependencies using go get. The specific Redis client adapter used will determine the included Redis library. ```bash go get github.com/go-redsync/redsync/v4 ``` -------------------------------- ### Configuration Example for Redigo Pool Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Provides an example of configuring a Redigo pool with various options like timeouts, password, and database selection. ```go pool := &redis.Pool{ MaxIdle: 3, // Maximum idle connections MaxActive: 10, // Maximum active connections IdleTimeout: 240 * time.Second, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "localhost:6379", redis.DialPassword("password"), redis.DialDatabase(0), redis.DialConnectTimeout(5*time.Second), redis.DialReadTimeout(5*time.Second), redis.DialWriteTimeout(5*time.Second), ) }, TestOnBorrow: func(c redis.Conn, t time.Time) error { if time.Since(t) < time.Minute { return nil } _, err := c.Do("PING") return err }, } redisPool := redigo.NewPool(pool) ``` -------------------------------- ### Usage Example for Redigo Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Shows how to create a Redigo pool, wrap it with the Redsync adapter, initialize Redsync, and use a mutex. ```go import ( "time" "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/redigo" "github.com/gomodule/redigo/redis" ) func main() { // Create a Redigo pool pool := &redis.Pool{ MaxIdle: 3, MaxActive: 10, IdleTimeout: 240 * time.Second, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "localhost:6379") }, TestOnBorrow: func(c redis.Conn, t time.Time) error { _, err := c.Do("PING") return err }, } // Wrap with Redsync adapter redisPool := redigo.NewPool(pool) // Create Redsync instance rs := redsync.New(redisPool) // Use mutexes mutex := rs.NewMutex("my-lock") if err := mutex.Lock(); err != nil { panic(err) } defer mutex.Unlock() } ``` -------------------------------- ### Usage Example: Valkey-Go with Redsync Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Demonstrates how to create a Valkey client, wrap it with the compatibility layer, and then use it with the Redsync library to manage distributed locks. ```go import ( "context" "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/valkeygo" "github.com/valkey-io/valkey-go" "github.com/valkey-io/valkey-go/valkeycompat" ) func main() { // Create a Valkey client client, err := valkey.NewClient(valkey.ClientOption{ InitAddress: []string{"localhost:6379"}, }) if err != nil { panic(err) } defer client.Close() // Use compatibility layer compatClient := valkeycompat.NewAdapter(client) // Wrap with Redsync adapter pool := valkeygo.NewPool(compatClient) // Create Redsync instance rs := redsync.New(pool) // Use mutexes mutex := rs.NewMutex("my-lock") ctx := context.Background() if err := mutex.LockContext(ctx); err != nil { panic(err) } defer mutex.UnlockContext(ctx) } ``` -------------------------------- ### Usage Example for Go-redis v8 Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Demonstrates how to create a go-redis v8 client, wrap it with the Redsync pool adapter, and initialize a Redsync instance. ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v8" "github.com/go-redis/redis/v8" ) func main() { client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) pool := goredis.NewPool(client) rs := redsync.New(pool) } ``` -------------------------------- ### RedSync File Organization Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/README.md Illustrates the directory structure of the RedSync project, showing the location of core components, adapters, and examples. ```text redsync/ ├── doc.go # Package documentation ├── redsync.go # Redsync struct and options ├── mutex.go # Mutex implementation ├── error.go # Error types ├── scripts.go # Lua scripts ├── redis/ │ ├── redis.go # Pool and Conn interfaces │ ├── goredis/v9/goredis.go # Go-redis v9 adapter │ ├── goredis/v8/goredis.go # Go-redis v8 adapter │ ├── redigo/redigo.go # Redigo adapter │ ├── rueidis/rueidis.go # Rueidis adapter │ └── valkeygo/valkeygo.go # Valkey-Go adapter └── examples/ # Usage examples ``` -------------------------------- ### Rueidis Usage Example with Go-Redsync Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Demonstrates how to create a Rueidis client, wrap it with the compatibility layer, and then use it with the Go-Redsync pool adapter to manage mutexes. ```go import ( "context" "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/rueidis" "github.com/redis/rueidis" "github.com/redis/rueidis/rueidiscompat" ) func main() { // Create a Rueidis client client, err := rueidis.NewClient(rueidis.ClientOption{ InitAddress: []string{"localhost:6379"}, }) if err != nil { panic(err) } defer client.Close() // Use compatibility layer compatClient := rueidiscompat.NewAdapter(client) // Wrap with Redsync adapter pool := rueidis.NewPool(compatClient) // Create Redsync instance rs := redsync.New(pool) // Use mutexes mutex := rs.NewMutex("my-lock") ctx := context.Background() if err := mutex.LockContext(ctx); err != nil { panic(err) } defer mutex.UnlockContext(ctx) } ``` -------------------------------- ### Catch context.Canceled with LockContext Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/errors.md Demonstrates catching `context.Canceled` when using `LockContext`. This example simulates cancellation by a separate goroutine after a short delay. ```go ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(1 * time.Second) cancel() // Cancel after 1 second }() if err := mutex.LockContext(ctx); err != nil { if errors.Is(err, context.Canceled) { fmt.Println("Operation was cancelled") return } panic(err) } ``` -------------------------------- ### Custom Redis Pool Implementation in Go Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Implement the `redsyncredis.Pool` interface to support custom Redis clients. This example shows a hypothetical client integration. ```go package myredis import ( "context" "time" redsyncredis "github.com/go-redsync/redsync/v4/redis" ) type pool struct { delegate MyCustomRedisPool } func NewPool(delegate MyCustomRedisPool) redsyncredis.Pool { return &pool{delegate} } func (p *pool) Get(ctx context.Context) (redsyncredis.Conn, error) { return &conn{p.delegate.GetConn()}, } type conn struct { delegate MyCustomRedisConn } func (c *conn) Get(name string) (string, error) { return c.delegate.Get(name) } func (c *conn) Set(name string, value string) (bool, error) { err := c.delegate.Set(name, value) return err == nil, err } func (c *conn) SetNX(name string, value string, expiry time.Duration) (bool, error) { ok, err := c.delegate.SetIfNotExists(name, value, expiry) return ok, err } func (c *conn) Eval(script *redsyncredis.Script, keysAndArgs ...any) (any, error) { return c.delegate.EvalScript(script.Hash, script.KeyCount, keysAndArgs...) } func (c *conn) ScriptLoad(script *redsyncredis.Script) error { hash, err := c.delegate.LoadScript(script.Src) if err == nil { script.Hash = hash } return err } func (c *conn) PTTL(name string) (time.Duration, error) { ttl, err := c.delegate.GetTTL(name) return time.Duration(ttl) * time.Millisecond, err } func (c *conn) Close() error { return c.delegate.Close() } ``` -------------------------------- ### High-Availability Setup with Multiple Redis Pools Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/README.md Demonstrates initializing Redsync with multiple Redis pools for high availability. The quorum is set to 2, meaning 2 out of 3 pools must acknowledge the lock. ```go pool1 := goredis.NewPool(redis.NewClient(&redis.Options{Addr: "redis1:6379"})) pool2 := goredis.NewPool(redis.NewClient(&redis.Options{Addr: "redis2:6379"})) pool3 := goredis.NewPool(redis.NewClient(&redis.Options{Addr: "redis3:6379"})) rs := redsync.New(pool1, pool2, pool3) // Quorum = 2 mutex := rs.NewMutex("resource") if err := mutex.Lock(); err != nil { return err } defer mutex.Unlock() ``` -------------------------------- ### Get Redis Key Time To Live Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Retrieves the remaining time-to-live for a key in Redis. Returns the duration or an error if the key does not exist or has no expiry. ```go PTTL(name string) (time.Duration, error) ``` -------------------------------- ### Get Mutex Name Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/mutex.md Retrieves the Redis key used for the distributed lock. This is the name provided during mutex creation. ```go mutex := rs.NewMutex("my-global-lock") lockName := mutex.Name() // Returns "my-global-lock" ``` -------------------------------- ### Recommended Production Configuration Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Use this configuration for general production use cases, balancing performance and reliability. ```go mutex := rs.NewMutex("production-lock", redsync.WithExpiry(10 * time.Second), redsync.WithTries(64), redsync.WithRetryDelay(100 * time.Millisecond), redsync.WithFailFast(true), redsync.WithShufflePools(true), redsync.WithSetNXOnExtend(), ) ``` -------------------------------- ### Redigo Pool Interface Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Defines the expected interface for a Redigo pool that the Redsync adapter will use. It requires methods for getting connections. ```go type Pool interface { Get() redis.Conn GetContext(ctx context.Context) (redis.Conn, error) } ``` -------------------------------- ### Typical Usage of Redsync in Go Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/README.md Demonstrates the standard pattern for initializing Redsync, creating a mutex, acquiring a lock, and executing critical sections. Ensure Redis is accessible at the specified address. ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) // Create Redis client client := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) pool := goredis.NewPool(client) // Create Redsync instance rs := redsync.New(pool) // Create and use mutex mutex := rs.NewMutex("my-lock") if err := mutex.Lock(); err != nil { panic(err) } def mutex.Unlock() // Critical section doExclusiveWork() ``` -------------------------------- ### Minimal RedSync Configuration Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Uses all default settings: 8s expiry, 32 tries, and random 50-250ms delays. This is the simplest way to initialize RedSync. ```go rs := redsync.New(pool) mutex := rs.NewMutex("my-lock") ``` -------------------------------- ### Get Redis Key Value Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Retrieves the string value of a key from Redis. Returns an error for missing keys, consistent with Redis behavior. ```go Get(name string) (string, error) ``` -------------------------------- ### Go-redis v9 Cluster and Sentinel Support Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Demonstrates how to create Redsync pool adapters for go-redis v9 cluster and sentinel configurations. The `UniversalClient` handles different topologies. ```go // Cluster clusterClient := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{"node1:6379", "node2:6379", "node3:6379"}, }) pool := goredis.NewPool(clusterClient) // Sentinel sentinelClient := redis.NewSentinelClient(&redis.SentinelOptions{ Addrs: []string{"sentinel1:26379", "sentinel2:26379"}, }) pool := goredis.NewPool(sentinelClient) ``` -------------------------------- ### Create Redsync Instance Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Initializes a new Redsync instance with the provided Redis pool. ```go rs := redsync.New(pool) ``` -------------------------------- ### Valkey-Go Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Wraps a Valkey-compatible client from github.com/valkey-io/valkey-go/valkeycompat to be used with Redsunc. ```APIDOC ## NewPool (Valkey-Go) ### Description Wraps a Valkey-compatible client from `github.com/valkey-io/valkey-go/valkeycompat` to create a Redsunc `Pool`. ### Function Signature `NewPool(delegate valkeycompat.Cmdable) Pool` ``` -------------------------------- ### Obtain and Release Distributed Lock with Redsync Source: https://github.com/go-redsync/redsync/blob/master/README.md Demonstrates how to create a Redis connection pool, instantiate Redsync, obtain a mutex, lock it, perform work, and then unlock it. Ensure the Redis client and pool implementations are correctly set up. Error handling is simplified to panic. ```go package main import ( goredislib "github.com/redis/go-redis/v9" "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" ) func main() { // Create a pool with go-redis (or redigo) which is the pool redsync will // use while communicating with Redis. This can also be any pool that // implements the `redis.Pool` interface. client := goredislib.NewClient(&goredislib.Options{ Addr: "localhost:6379", }) pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...) // Create an instance of redsync to be used to obtain a mutual exclusion // lock. rs := redsync.New(pool) // Obtain a new mutex by using the same name for all instances wanting the // same lock. mutexname := "my-global-mutex" mutex := rs.NewMutex(mutexname) // Obtain a lock for our given mutex. After this is successful, no one else // can obtain the same lock (the same mutex name) until we unlock it. if err := mutex.Lock(); err != nil { panic(err) } // Do your work that requires the lock. // Release the lock so other processes or threads can obtain a lock. if ok, err := mutex.Unlock(); !ok || err != nil { panic("unlock failed") } } ``` -------------------------------- ### PTTL Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Gets the remaining time-to-live of a key in milliseconds. This is used to check the remaining validity of a lock. Negative values have specific meanings per Redis semantics. ```APIDOC ## PTTL ### Description Gets the remaining time-to-live of a key in milliseconds. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - **name** (`string`) - Required - Redis key name ### Request Example ```json { "name": "mykey" } ``` ### Response #### Success Response (200) - `time.Duration` - The remaining TTL as a duration. Returns -2 if the key does not exist, -1 if the key exists but has no associated TTL. #### Response Example ```json { "duration": "10s" } ``` ### Throws/Errors - Communication errors with Redis ``` -------------------------------- ### New Pool Adapter for Rueidis Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a pool adapter for Go-Redsync from a Rueidis-compatible client. Requires a delegate of type `rueidiscompat.Cmdable`. ```go func NewPool(delegate rueidiscompat.Cmdable) redis.Pool ``` -------------------------------- ### Conn Interface - Get Method Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Retrieves the value of a key from Redis. If the key does not exist, an error is returned, normalized to a nil error following the Redis abstraction pattern. ```APIDOC ## Conn.Get ### Description Retrieves the value of a key from Redis. If the key does not exist, an error is returned (implementations normalize this to nil error following the Redis abstraction pattern). ### Method `Get(name string) (string, error)` ### Parameters #### Path Parameters - **name** (string) - Required - Redis key name ### Response #### Success Response (string, error) The string value stored at the key, or an error if not found or communication fails. #### Error Response - Returns error (not a nil result) for missing keys, consistent with Redis behavior ``` -------------------------------- ### Low-Latency Configuration Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Prioritize low latency by minimizing expiry, retries, and retry delay. ```go mutex := rs.NewMutex("low-latency", redsync.WithExpiry(3 * time.Second), redsync.WithTries(8), redsync.WithRetryDelay(10 * time.Millisecond), redsync.WithFailFast(true), ) ``` -------------------------------- ### Get Mutex Value Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/mutex.md Retrieves the current random value associated with the lock. This value is used to verify ownership when releasing the lock and is set after successful acquisition or via WithValue option. ```go mutex := rs.NewMutex("my-lock") // Value is empty before lock acquisition val := mutex.Value() // Returns "" // Lock is acquired if err := mutex.Lock(); err != nil { panic(err) } // Value is now set val = mutex.Value() // Returns a base64-encoded random string // Can transfer to another mutex anotherMutex := rs.NewMutex("my-lock", redsync.WithValue(val)) ``` -------------------------------- ### Create Redsync Instance Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redsync.md Initializes a Redsync instance with one or more Redis connection pools. For production, use at least 3 pools for availability, or 5 for higher safety margins. The algorithm requires a majority of pools to agree on lock acquisition. ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" goredislib "github.com/redis/go-redis/v9" ) func main() { // Create a Redis client client := goredislib.NewClient(&goredislib.Options{ Addr: "localhost:6379", }) // Create a pool adapter pool := goredis.NewPool(client) // Create a Redsync instance with one pool rs := redsync.New(pool) // Or create with multiple pools for higher availability client2 := goredislib.NewClient(&goredislib.Options{ Addr: "localhost:6380", }) pool2 := goredis.NewPool(client2) rs := redsync.New(pool, pool2) } ``` -------------------------------- ### Pool Interface - Get Method Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Retrieves a connection from the pool. Implementations manage connection lifecycle, reuse, and cleanup. The returned connection should be released back to the pool using the Close() method on the Conn interface. ```APIDOC ## Pool.Get ### Description Retrieves a connection from the pool. The pool manages connection lifecycle, reuse, and cleanup. The returned connection should be used and then released back to the pool via the `Close()` method on the `Conn` interface. ### Method `Get(ctx context.Context) (Conn, error)` ### Parameters #### Path Parameters - **ctx** (context.Context) - Required - Context for cancellation and timeouts ### Response #### Success Response (Conn, error) Returns a `Conn` implementation ready to use. #### Error Response - Connection errors if unable to establish a connection - Context cancellation or deadline exceeded ``` -------------------------------- ### Configure Redsync Fail-Fast Mode Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Use `WithFailFast` to enable fast-fail mode, returning immediately once a quorum is confirmed. This reduces latency but offers a slightly lower safety margin. Recommended for high-throughput scenarios. ```go apiMutex := rs.NewMutex("api-endpoint", redsync.WithFailFast(true), redsync.WithTries(16)) financialMutex := rs.NewMutex("payment-processing", redsync.WithFailFast(false), redsync.WithTries(64)) ``` -------------------------------- ### Get Mutex Expiration Time Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/mutex.md Retrieves the time when the acquired lock is set to expire. Returns the zero time value until a lock is acquired. After acquisition or extension, it represents the lock's validity deadline, though it might expire sooner due to clock drift. ```go mutex := rs.NewMutex("my-lock") if err := mutex.Lock(); err != nil { panic(err) } // Check when the lock expires expiresAt := mutex.Until() timeRemaining := time.Until(expiresAt) if timeRemaining < 1*time.Second { // Extend the lock if it's about to expire if ok, err := mutex.Extend(); !ok || err != nil { panic("extension failed") } } ``` -------------------------------- ### Create Redis Pool with Go-Redis Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Creates a Redis client using go-redis and wraps it with a Redsync adapter for use with Redsync. ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) // Create Redis client client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) // Wrap with Redsync adapter pool := goredis.NewPool(client) ``` -------------------------------- ### Go-redis v8 Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Wraps a redis.UniversalClient from github.com/go-redis/redis/v8 to be used with Redsunc. ```APIDOC ## NewPool (Go-redis v8) ### Description Wraps a `redis.UniversalClient` from `github.com/go-redis/redis/v8` to create a Redsunc `Pool`. ### Function Signature `NewPool(delegate redis.UniversalClient) Pool` ``` -------------------------------- ### Recommended Production RedSync Configuration Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Configures RedSync for production use with specific settings for expiry, retries, retry delay, drift factor, fail fast behavior, pool shuffling, and using SetNX on extend. Recommended for most production environments. ```go mutex := rs.NewMutex("production-lock", redsync.WithExpiry(10 * time.Second), redsync.WithTries(64), redsync.WithRetryDelay(100 * time.Millisecond), redsync.WithDriftFactor(0.01), redsync.WithFailFast(true), redsync.WithShufflePools(true), redsync.WithSetNXOnExtend(), ) ``` -------------------------------- ### Valkey-Go Pool Adapter Constructor Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a pool adapter from a Valkey-compatible client. This is used to bridge the Valkey-Go client library with Redsync. ```go func NewPool(delegate valkeycompat.Cmdable) redis.Pool ``` -------------------------------- ### Create Go-redis v8 Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a Redsync pool adapter from a go-redis v8 UniversalClient. This is used to integrate go-redis v8 with Redsync. ```go func NewPool(delegate redis.UniversalClient) redis.Pool ``` -------------------------------- ### Go: Context-Based Locking with Timeouts Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Integrates lock acquisition with request timeouts and cancellation using Go's context package. Essential for managing long-running operations and preventing deadlocks. ```go ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() mutex := rs.NewMutex("resource") if err := mutex.LockContext(ctx); err != nil { if errors.Is(err, context.DeadlineExceeded) { log.Println("Lock acquisition timed out") return } log.Printf("Lock failed: %v", err) return } defer mutex.UnlockContext(ctx) doWork() ``` -------------------------------- ### NewPool Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a pool adapter from a Valkey-compatible client. This allows Redsync to interact with Valkey servers. ```APIDOC ## NewPool ### Description Creates a pool adapter from a Valkey-compatible client. ### Method func ### Signature func NewPool(delegate valkeycompat.Cmdable) redis.Pool ### Parameters #### Path Parameters - delegate (valkeycompat.Cmdable) - Required - A Valkey compatibility-layer client ### Return Type redis.Pool ``` -------------------------------- ### NewPool Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a pool adapter from a Rueidis-compatible client. ```APIDOC ## NewPool ### Description Creates a pool adapter from a Rueidis-compatible client. ### Method func ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **delegate** (`rueidiscompat.Cmdable`) - Required - A Rueidis compatibility-layer client ### Return Type `redis.Pool` ### Usage Example ```go import ( "context" "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/rueidis" "github.com/redis/rueidis" "github.com/redis/rueidis/rueidiscompat" ) func main() { // Create a Rueidis client client, err := rueidis.NewClient(rueidis.ClientOption{ InitAddress: []string{"localhost:6379"}, }) if err != nil { panic(err) } defer client.Close() // Use compatibility layer compatClient := rueidiscompat.NewAdapter(client) // Wrap with Redsync adapter pool := rueidis.NewPool(compatClient) // Create Redsync instance rs := redsync.New(pool) // Use mutexes mutex := rs.NewMutex("my-lock") ctx := context.Background() if err := mutex.LockContext(ctx); err != nil { panic(err) } defer mutex.UnlockContext(ctx) } ``` ``` -------------------------------- ### NewPool (go-redis v9) Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Creates a pool adapter from a go-redis v9 UniversalClient, enabling seamless integration with Redsync. ```APIDOC ## NewPool (go-redis v9) ### Description Creates a pool adapter from a go-redis v9 `UniversalClient`. ### Method func ### Signature func NewPool(delegate redis.UniversalClient) redis.Pool ### Parameters #### Path Parameters - **delegate** (redis.UniversalClient) - Required - A go-redis v9 universal client instance ### Return Type redis.Pool A pool implementation compatible with Redsync. ### Usage Example ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) func main() { // Create a go-redis client client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) // Wrap with the Redsync adapter pool := goredis.NewPool(client) // Create Redsync instance rs := redsync.New(pool) // Use mutexes as normal mutex := rs.NewMutex("my-lock") if err := mutex.Lock(); err != nil { panic(err) } defer mutex.Unlock() } ``` ### Cluster and Sentinel Support The `UniversalClient` supports standalone, cluster, and sentinel topologies. The adapter passes through all client types: ```go // Cluster clusterClient := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{"node1:6379", "node2:6379", "node3:6379"}, }) pool := goredis.NewPool(clusterClient) // Sentinel sentinelClient := redis.NewSentinelClient(&redis.SentinelOptions{ Addrs: []string{"sentinel1:26379", "sentinel2:26379"}, }) pool := goredis.NewPool(sentinelClient) ``` ``` -------------------------------- ### Go-redis v9 Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Wraps a redis.UniversalClient from github.com/redis/go-redis/v9 to be used with Redsunc. ```APIDOC ## NewPool (Go-redis v9) ### Description Wraps a `redis.UniversalClient` from `github.com/redis/go-redis/v9` to create a Redsunc `Pool`. ### Function Signature `NewPool(delegate redis.UniversalClient) Pool` ### Usage Example ```go import ( "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) pool := goredis.NewPool(client) rs := redsync.New(pool) ``` ``` -------------------------------- ### Go-redis v9 Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Wraps a redis.UniversalClient from github.com/redis/go-redis/v9. Use this when integrating with go-redis v9. ```go import ( "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) pool := goredis.NewPool(client) rs := redsync.New(pool) ``` -------------------------------- ### Configure Redsync Robust Lock Extension Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Use `WithSetNXOnExtend` to improve lock extension by re-acquiring the lock if the key has expired. This reduces lock loss during Redis restarts. Recommended for production environments. ```go robustMutex := rs.NewMutex("critical-section", redsync.WithSetNXOnExtend()) simpleMutex := rs.NewMutex("simple-lock") ``` -------------------------------- ### New Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redsync.md Creates and returns a new Redsync instance from given Redis connection pools. The Redsync instance aggregates multiple Redis pools, which is essential for achieving the distributed locking algorithm. Typically, you should provide at least 3 pools for production use (or 5 for higher safety margins), though the minimum is 1. The algorithm requires a quorum (majority) of pools to agree on lock acquisition. ```APIDOC ## New ### Description Creates and returns a new `Redsync` instance from given Redis connection pools. ### Signature `New(pools ...redis.Pool) *Redsync` ### Parameters #### Path Parameters - **pools** (`...redis.Pool`) - Required - Variable number of Redis pool implementations that implement the `redis.Pool` interface ### Return Type `*Redsync` A pointer to a newly created `Redsync` instance configured with the provided pools. ### Usage Example ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" goredislib "github.com/redis/go-redis/v9" ) func main() { // Create a Redis client client := goredislib.NewClient(&goredislib.Options{ Addr: "localhost:6379", }) // Create a pool adapter pool := goredis.NewPool(client) // Create a Redsync instance with one pool rs := redsync.New(pool) // Or create with multiple pools for higher availability client2 := goredislib.NewClient(&goredislib.Options{ Addr: "localhost:6380", }) pool2 := goredis.NewPool(client2) rs := redsync.New(pool, pool2) } ``` ``` -------------------------------- ### Create Go-redis v9 Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/pool-adapters.md Use this to create a Redsync pool adapter from a go-redis v9 `UniversalClient`. This adapter is compatible with Redsync's mutex operations. ```go import ( "github.com/go-redsync/redsync/v4" "github.com/go-redsync/redsync/v4/redis/goredis/v9" "github.com/redis/go-redis/v9" ) func main() { // Create a go-redis client client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) // Wrap with the Redsync adapter pool := goredis.NewPool(client) // Create Redsync instance rs := redsync.New(pool) // Use mutexes as normal mutex := rs.NewMutex("my-lock") if err := mutex.Lock(); err != nil { panic(err) } defer mutex.Unlock() } ``` -------------------------------- ### Use Multiple Pools for Production Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md In production environments, utilize multiple Redis pools to distribute lock requests and improve availability. A minimum of three pools is recommended. ```go rs := redsync.New(pool1, pool2, pool3) // 3+ pools recommended ``` -------------------------------- ### Create New Script Object Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Creates a new Script object. The hash parameter should be a pre-computed SHA1 hash of the script source for optimized EVALSHA execution. ```go script := redis.NewScript(1, " local val = redis.call(\"GET\", KEYS[1]) if val == ARGV[1] then return redis.call(\"DEL\", KEYS[1]) else return 0 end ", "e950836ed1e694540c503ef9972b8de518044d3b") ``` ```go // Use the script result, err := conn.Eval(script, "my-key", "expected-value") ``` -------------------------------- ### Context-Based Locking for API Endpoints Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/README.md Shows how to implement context-aware locking for API requests, ensuring locks are released or timeouts are handled gracefully. This pattern is useful for preventing race conditions in concurrent API calls. ```go func handleRequest(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second) defer cancel() mutex := rs.NewMutex("api-resource") if err := mutex.LockContext(ctx); err != nil { http.Error(w, "Lock timeout", http.StatusServiceUnavailable) return } defer mutex.UnlockContext(ctx) w.WriteHeader(http.StatusOK) } ``` -------------------------------- ### TryLock: Acquire Lock Once (Go) Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/mutex.md Use `TryLock` for a non-blocking, immediate attempt to acquire a lock. It returns `ErrFailed` if the lock is already held. This is suitable for fast, fail-fast locking scenarios. ```go mutex := rs.NewMutex("my-lock") if err := mutex.TryLock(); err != nil { if errors.Is(err, redsync.ErrFailed) { fmt.Println("Lock is already held, skipping work") return } panic(err) } // Do critical work fmt.Println("Lock acquired!") if ok, err := mutex.Unlock(); !ok || err != nil { panic("unlock failed") } ``` -------------------------------- ### Redsync Type Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/INDEX.md Provides methods for creating and configuring Redsync instances. ```APIDOC ## Redsync Type ### Constructor - `New()` — Create Redsync instance ### Methods - `NewMutex(name string, options ...Option) Mutex` — Create mutex ### Configuration Options - `WithExpiry(expiry time.Duration) Option` - `WithTries(tries int) Option` - `WithRetryDelay(delay time.Duration) Option` - `WithRetryDelayFunc(delayFunc DelayFunc) Option` - `WithDriftFactor(factor float64) Option` - `WithTimeoutFactor(factor float64) Option` - `WithGenValueFunc(genValueFunc func() (string, error)) Option` - `WithValue(v string) Option` - `WithFailFast(b bool) Option` - `WithShufflePools(b bool) Option` - `WithSetNXOnExtend() Option` ``` -------------------------------- ### Define Custom Mutex Option with OptionFunc Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redsync.md Illustrates how to create a custom mutex option using the OptionFunc type, which simplifies implementing the Option interface for inline definitions. ```go type Option interface { Apply(*Mutex) } ``` ```go type OptionFunc func(*Mutex) func (f OptionFunc) Apply(mutex *Mutex) { f(mutex) } ``` -------------------------------- ### Configuration Options Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/INDEX.md Options to configure the behavior of Redsync, such as lock expiry, retries, and delays. ```APIDOC ## WithExpiry(expiry time.Duration) ### Description Sets the lock's time-to-live (TTL) duration. ### Method WithExpiry ### Endpoint N/A (SDK Option) ### Parameters - **expiry** (time.Duration) - The duration for which the lock should be considered valid. ### Request Example ```go // Configure a lock with a 30-second expiry rs := redsync.New(pool, redsync.WithExpiry(30*time.Second)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithTries(tries int) ### Description Sets the number of lock acquisition attempts. ### Method WithTries ### Endpoint N/A (SDK Option) ### Parameters - **tries** (int) - The maximum number of times to attempt acquiring the lock. ### Request Example ```go // Configure Redsync to try acquiring the lock up to 5 times rs := redsync.New(pool, redsync.WithTries(5)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithRetryDelay(delay time.Duration) ### Description Sets a fixed delay between lock acquisition attempts. ### Method WithRetryDelay ### Endpoint N/A (SDK Option) ### Parameters - **delay** (time.Duration) - The fixed duration to wait between retries. ### Request Example ```go // Configure a 100ms delay between retries rs := redsync.New(pool, redsync.WithRetryDelay(100*time.Millisecond)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithRetryDelayFunc(delayFunc func() time.Duration) ### Description Sets a custom function to determine the delay between lock acquisition attempts. ### Method WithRetryDelayFunc ### Endpoint N/A (SDK Option) ### Parameters - **delayFunc** (func() time.Duration) - A function that returns the duration to wait before the next retry. ### Request Example ```go // Configure a custom retry delay function (e.g., exponential backoff) rs := redsync.New(pool, redsync.WithRetryDelayFunc(func() time.Duration { // custom logic for delay return 50 * time.Millisecond })) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithSetNXOnExtend() ### Description Ensures that extending a lock only succeeds if the lock is still held by the current client (using SETNX semantics for extension). ### Method WithSetNXOnExtend ### Endpoint N/A (SDK Option) ### Parameters None ### Request Example ```go // Use SETNX semantics when extending locks rs := redsync.New(pool, redsync.WithSetNXOnExtend()) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithDriftFactor(factor float64) ### Description Configures the clock drift factor, which is a margin used to account for clock differences between servers. ### Method WithDriftFactor ### Endpoint N/A (SDK Option) ### Parameters - **factor** (float64) - The clock drift factor. Defaults to 0.01. ### Request Example ```go // Set a clock drift factor of 0.05 rs := redsync.New(pool, redsync.WithDriftFactor(0.05)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithTimeoutFactor(factor float64) ### Description Configures the factor used to calculate Redis operation timeouts based on the lock's expiry. ### Method WithTimeoutFactor ### Endpoint N/A (SDK Option) ### Parameters - **factor** (float64) - The timeout factor. Defaults to 0.5. ### Request Example ```go // Set a timeout factor of 0.7 rs := redsync.New(pool, redsync.WithTimeoutFactor(0.7)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithFailFast(b bool) ### Description Determines whether the operation should fail fast if the quorum cannot be met. ### Method WithFailFast ### Endpoint N/A (SDK Option) ### Parameters - **b** (bool) - If true, the operation fails immediately if quorum is not reached. Defaults to false. ### Request Example ```go // Enable fail-fast behavior rs := redsync.New(pool, redsync.WithFailFast(true)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithShufflePools(b bool) ### Description Determines whether the order of Redis pools should be randomized for each operation. ### Method WithShufflePools ### Endpoint N/A (SDK Option) ### Parameters - **b** (bool) - If true, the pool order is randomized. Defaults to false. ### Request Example ```go // Enable shuffling of Redis pools rs := redsync.New(pool, redsync.WithShufflePools(true)) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithGenValueFunc(genValueFunc func() (string, error)) ### Description Sets a custom function to generate the value associated with the lock. ### Method WithGenValueFunc ### Endpoint N/A (SDK Option) ### Parameters - **genValueFunc** (func() (string, error)) - A function that returns the lock value and an error. ### Request Example ```go // Use a custom function to generate lock values rs := redsync.New(pool, redsync.WithGenValueFunc(func() (string, error) { // custom value generation logic return "my-custom-value", nil })) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` ```APIDOC ## WithValue(v string) ### Description Sets a pre-defined value for the lock. ### Method WithValue ### Endpoint N/A (SDK Option) ### Parameters - **v** (string) - The value to associate with the lock. ### Request Example ```go // Set a specific value for the lock rs := redsync.New(pool, redsync.WithValue("my-static-value")) ``` ### Response Returns an Option that can be passed to the Redsync constructor. ``` -------------------------------- ### High-Throughput Configuration Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Optimize for APIs and high-frequency operations by reducing expiry, retries, and retry delay. ```go mutex := rs.NewMutex("api-endpoint", redsync.WithExpiry(2 * time.Second), redsync.WithTries(4), redsync.WithRetryDelay(5 * time.Millisecond), redsync.WithFailFast(true), ) ``` -------------------------------- ### Go: Custom Retry with Exponential Backoff Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/quickstart.md Implements custom retry logic with exponential backoff for acquiring locks in high-contention scenarios. Allows fine-grained control over retry attempts and delays. ```go mutex := rs.NewMutex("contested-resource", redsync.WithTries(128), redsync.WithRetryDelayFunc(func(tries int) time.Duration { delay := time.Duration(50 * (1 << uint(tries))) * time.Millisecond if delay > 5*time.Second { delay = 5 * time.Second } return delay }), ) if err := mutex.Lock(); err != nil { log.Printf("Failed to acquire lock: %v", err) return } defer mutex.Unlock() doWork() ``` -------------------------------- ### Configure Mutex Expiry with WithExpiry Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Use `WithExpiry` to set the time-to-live for a lock. Adjust based on task duration and desired recovery time. Shorter TTLs are for fast tasks, longer TTLs for slow tasks. ```go fastMutex := rs.NewMutex("quick-operation", redsync.WithExpiry(3*time.Second)) slowMutex := rs.NewMutex("batch-job", redsync.WithExpiry(30*time.Second)) ``` -------------------------------- ### Redigo Pool Adapter Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/api-reference/redis-interface.md Wraps a Redigo pool (github.com/gomodule/redigo/redis.Pool). Use this when integrating with Redigo. ```go import ( "github.com/go-redsync/redsync/v4/redis/redigo" "github.com/gomodule/redigo/redis" ) pool := &redis.Pool{ Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "localhost:6379") }, } redisPool := redigo.NewPool(pool) rs := redsync.New(redisPool) ``` -------------------------------- ### Configure Custom Retry Delay Function Source: https://github.com/go-redsync/redsync/blob/master/_autodocs/configuration.md Use `WithRetryDelayFunc` to provide a custom function that calculates the delay between lock acquisition attempts based on the current try count. This allows for complex backoff strategies like linear, exponential, or jittered delays. ```go linearMutex := rs.NewMutex("linear-retry", redsync.WithRetryDelayFunc(func(tries int) time.Duration { return time.Duration(100 * (tries + 1)) * time.Millisecond }), ) ``` ```go exponentialMutex := rs.NewMutex("exp-retry", redsync.WithRetryDelayFunc(func(tries int) time.Duration { return time.Duration(10 * (1 << uint(tries))) * time.Millisecond }), ) ``` ```go jitteredMutex := rs.NewMutex("jittered-retry", redsync.WithRetryDelayFunc(func(tries int) time.Duration { return time.Duration(50+rand.Intn(100)) * time.Millisecond }), ) ``` ```go cappedMutex := rs.NewMutex("capped-exp", redsync.WithRetryDelayFunc(func(tries int) time.Duration { delay := time.Duration(10 * (1 << uint(tries))) * time.Millisecond if delay > 500*time.Millisecond { delay = 500 * time.Millisecond } return delay }), ) ```