Documentation
¶
Overview ¶
Package redis provides Redis/Valkey client helpers with topology and IAM support.
Supported deployment modes include standalone, sentinel, and cluster. Authentication supports static passwords and short-lived GCP IAM tokens with automatic refresh and reconnect.
Index ¶
- Variables
- func SetPackageLogger(l log.Logger)
- type Auth
- type Client
- type ClusterTopology
- type Config
- type ConnectionOptions
- type GCPIAMAuth
- type LockHandle
- type LockManager
- type LockOptions
- type RedisLockManager
- func (dl *RedisLockManager) TryLock(ctx context.Context, lockKey string) (LockHandle, bool, error)
- func (dl *RedisLockManager) Unlock(ctx context.Context, handle LockHandle) errordeprecated
- func (dl *RedisLockManager) WithLock(ctx context.Context, lockKey string, fn func(context.Context) error) error
- func (dl *RedisLockManager) WithLockOptions(ctx context.Context, lockKey string, opts LockOptions, ...) error
- type SentinelTopology
- type StandaloneTopology
- type StaticPasswordAuth
- type Status
- type TLSConfig
- type Topology
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNilLockHandle is returned when a nil or uninitialized lock handle is used. ErrNilLockHandle = errors.New("lock handle is nil or not initialized") // ErrLockNotHeld is returned when unlock is called on a lock that was not held or already expired. ErrLockNotHeld = errors.New("lock was not held or already expired") // ErrNilLockManager is returned when a method is called on a nil RedisLockManager. ErrNilLockManager = errors.New("lock manager is nil") // ErrLockNotInitialized is returned when the distributed lock's redsync is not initialized. ErrLockNotInitialized = errors.New("distributed lock is not initialized") // ErrNilLockFn is returned when a nil function is passed to WithLock. ErrNilLockFn = errors.New("lock function is nil") // ErrEmptyLockKey is returned when an empty lock key is provided. ErrEmptyLockKey = errors.New("lock key cannot be empty") // ErrLockExpiryInvalid is returned when lock expiry is not positive. ErrLockExpiryInvalid = errors.New("lock expiry must be greater than 0") // ErrLockTriesInvalid is returned when lock tries is less than 1. ErrLockTriesInvalid = errors.New("lock tries must be at least 1") // ErrLockTriesExceeded is returned when lock tries exceeds the maximum. ErrLockTriesExceeded = errors.New("lock tries exceeds maximum") // ErrLockRetryDelayNegative is returned when retry delay is negative. ErrLockRetryDelayNegative = errors.New("lock retry delay cannot be negative") // ErrLockDriftFactorInvalid is returned when drift factor is outside [0, 1). ErrLockDriftFactorInvalid = errors.New("lock drift factor must be between 0 (inclusive) and 1 (exclusive)") // ErrNilLockHandleOnUnlock is returned when Unlock is called with a nil handle. ErrNilLockHandleOnUnlock = errors.New("lock handle is nil") )
var ( // ErrNilClient is returned when a redis client receiver is nil. ErrNilClient = errors.New("redis client is nil") // ErrInvalidConfig indicates the provided redis configuration is invalid. ErrInvalidConfig = errors.New("invalid redis config") )
Functions ¶
func SetPackageLogger ¶ added in v2.3.0
SetPackageLogger configures a package-level logger used for nil-receiver assertion diagnostics and telemetry reporting. This is typically called once during application bootstrap. If l is nil, a NopLogger is used.
Types ¶
type Auth ¶
type Auth struct {
StaticPassword *StaticPasswordAuth
GCPIAM *GCPIAMAuth
}
Auth selects one Redis authentication strategy.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client wraps a redis.UniversalClient with reconnection and IAM token refresh logic.
func (*Client) Connect ¶
Connect establishes a Redis connection using the current client configuration.
func (*Client) GetClient ¶
GetClient returns a connected redis client, reconnecting on demand if needed.
func (*Client) IsConnected ¶
IsConnected reports whether the underlying client is currently connected.
func (*Client) LastRefreshError ¶
LastRefreshError returns the latest IAM refresh/reconnect error.
type ClusterTopology ¶
type ClusterTopology struct {
Addresses []string
}
ClusterTopology configures Redis cluster access.
type Config ¶
type Config struct {
Topology Topology
TLS *TLSConfig
Auth Auth
Options ConnectionOptions
Logger log.Logger
MetricsFactory *metrics.MetricsFactory
}
Config defines Redis client topology, auth, TLS, and connection settings.
type ConnectionOptions ¶
type ConnectionOptions struct {
DB int
Protocol int
PoolSize int
MinIdleConns int
ReadTimeout time.Duration
WriteTimeout time.Duration
DialTimeout time.Duration
PoolTimeout time.Duration
MaxRetries int
MinRetryBackoff time.Duration
MaxRetryBackoff time.Duration
}
ConnectionOptions configures protocol, timeouts, pools, and retries.
type GCPIAMAuth ¶
type GCPIAMAuth struct {
CredentialsBase64 string
ServiceAccount string
TokenLifetime time.Duration
RefreshEvery time.Duration
RefreshCheckInterval time.Duration
RefreshOperationTimeout time.Duration
}
GCPIAMAuth authenticates with short-lived GCP IAM access tokens.
func (GCPIAMAuth) GoString ¶ added in v2.3.0
func (a GCPIAMAuth) GoString() string
GoString returns a redacted representation for fmt %#v.
func (GCPIAMAuth) String ¶ added in v2.3.0
func (a GCPIAMAuth) String() string
String returns a redacted representation to prevent accidental credential logging.
type LockHandle ¶ added in v2.3.0
type LockHandle interface {
// Unlock releases the distributed lock.
Unlock(ctx context.Context) error
}
LockHandle represents an acquired distributed lock. It is obtained from TryLock and must be released via its Unlock method.
Example usage:
handle, acquired, err := locker.TryLock(ctx, "lock:resource:123")
if err != nil {
return err
}
if !acquired {
return nil // lock busy, skip
}
defer handle.Unlock(ctx)
// ... critical section ...
type LockManager ¶ added in v2.3.0
type LockManager interface {
// WithLock executes a function while holding a distributed lock with default options.
// The lock is automatically released when the function returns.
WithLock(ctx context.Context, lockKey string, fn func(context.Context) error) error
// WithLockOptions executes a function while holding a distributed lock with custom options.
// Use this for fine-grained control over lock behavior.
WithLockOptions(ctx context.Context, lockKey string, opts LockOptions, fn func(context.Context) error) error
// TryLock attempts to acquire a lock without retrying.
// Returns the handle and true if lock was acquired, nil and false otherwise.
// Use LockHandle.Unlock to release the lock when done.
TryLock(ctx context.Context, lockKey string) (LockHandle, bool, error)
}
LockManager provides an interface for distributed locking operations. This interface allows for easy mocking in tests without requiring a real Redis instance.
Example test implementation:
type MockLockManager struct{}
func (m *MockLockManager) WithLock(ctx context.Context, lockKey string, fn func(context.Context) error) error {
// In tests, just execute the function without actual locking
return fn(ctx)
}
func (m *MockLockManager) WithLockOptions(ctx context.Context, lockKey string, opts LockOptions, fn func(context.Context) error) error {
return fn(ctx)
}
func (m *MockLockManager) TryLock(ctx context.Context, lockKey string) (LockHandle, bool, error) {
return &mockHandle{}, true, nil
}
type LockOptions ¶
type LockOptions struct {
// Expiry is how long the lock is held before auto-expiring (prevents deadlocks)
// Default: 10 seconds
Expiry time.Duration
// Tries is the number of attempts to acquire the lock before giving up
// Default: 3, Maximum: 1000
Tries int
// RetryDelay is the delay between retry attempts
// Default: 500ms
RetryDelay time.Duration
// DriftFactor accounts for clock drift in distributed systems (RedLock algorithm)
// Default: 0.01 (1%)
DriftFactor float64
}
LockOptions configures lock behavior for advanced use cases. Use DefaultLockOptions() for sensible defaults.
func DefaultLockOptions ¶
func DefaultLockOptions() LockOptions
DefaultLockOptions returns production-ready defaults for distributed locking. These values are tuned for typical microservice scenarios with: - Operations completing within seconds - Network latency < 100ms - Acceptable retry overhead
func RateLimiterLockOptions ¶
func RateLimiterLockOptions() LockOptions
RateLimiterLockOptions returns optimized defaults for rate limiter locking. These values are tuned for short, fast operations like rate limiting: - Quick operations (< 100ms) - Fast retry for better throughput - Lower expiry to reduce contention
type RedisLockManager ¶ added in v2.3.0
type RedisLockManager struct {
// contains filtered or unexported fields
}
RedisLockManager provides distributed locking capabilities using Redis and the RedLock algorithm. This implementation ensures mutual exclusion across multiple service instances, preventing race conditions in critical sections such as: - Password update operations - Cache invalidation - Rate limiting checks - Any other operation requiring distributed coordination
The RedLock algorithm provides strong guarantees even in the presence of: - Network partitions - Process crashes - Clock drift
Example usage:
lock, err := redis.NewRedisLockManager(redisClient)
if err != nil {
return err
}
err = lock.WithLock(ctx, "lock:user:123", func(ctx context.Context) error {
// Critical section - only one instance will execute this at a time
return updateUser(123)
})
func NewRedisLockManager ¶ added in v2.3.0
func NewRedisLockManager(conn *Client) (*RedisLockManager, error)
NewRedisLockManager creates a new distributed lock manager. The lock manager uses the RedLock algorithm for distributed consensus. It uses a lazy pool that resolves the latest Redis client per operation, surviving IAM token refresh reconnections.
Thread-safe: Yes - multiple goroutines can use the same RedisLockManager instance.
Example:
lock, err := redis.NewRedisLockManager(redisClient)
if err != nil {
return fmt.Errorf("failed to initialize lock: %w", err)
}
func (*RedisLockManager) TryLock ¶ added in v2.3.0
func (dl *RedisLockManager) TryLock(ctx context.Context, lockKey string) (LockHandle, bool, error)
TryLock attempts to acquire a lock without retrying. Returns the handle and true if lock was acquired, nil and false if lock is busy. Returns an error for unexpected failures (network errors, context cancellation, etc.)
Use LockHandle.Unlock to release the lock when done:
handle, acquired, err := lock.TryLock(ctx, "lock:cache:refresh")
if err != nil {
// Unexpected error (network, context cancellation, etc.) - should be propagated
return fmt.Errorf("failed to attempt lock acquisition: %w", err)
}
if !acquired {
logger.Info("Lock busy, skipping cache refresh")
return nil
}
defer handle.Unlock(ctx)
// Perform cache refresh...
func (*RedisLockManager) Unlock
deprecated
added in
v2.3.0
func (dl *RedisLockManager) Unlock(ctx context.Context, handle LockHandle) error
Unlock releases a previously acquired lock.
Deprecated: Use LockHandle.Unlock() directly instead. This method is provided for backward compatibility during migration from the old *redsync.Mutex-based API.
func (*RedisLockManager) WithLock ¶ added in v2.3.0
func (dl *RedisLockManager) WithLock(ctx context.Context, lockKey string, fn func(context.Context) error) error
WithLock executes a function while holding a distributed lock. The lock is automatically released when the function returns, even on panic.
Parameters:
- ctx: context for cancellation and tracing
- lockKey: unique identifier for the lock (e.g., "lock:user:123")
- fn: function to execute under lock
Returns:
- error: from fn() or lock acquisition failure
Example:
err := lock.WithLock(ctx, "lock:user:password:123", func(ctx context.Context) error {
return updatePassword(123, newPassword)
})
func (*RedisLockManager) WithLockOptions ¶ added in v2.3.0
func (dl *RedisLockManager) WithLockOptions(ctx context.Context, lockKey string, opts LockOptions, fn func(context.Context) error) error
WithLockOptions executes a function while holding a distributed lock with custom options. Use this when you need fine-grained control over lock behavior.
Example with custom timeout:
opts := redis.LockOptions{
Expiry: 30 * time.Second, // Long-running operation
Tries: 5, // More aggressive retries
RetryDelay: 1 * time.Second,
}
err := lock.WithLockOptions(ctx, "lock:report:generation", opts, func(ctx context.Context) error {
return generateReport()
})
type SentinelTopology ¶
SentinelTopology configures Redis Sentinel access.
type StandaloneTopology ¶
type StandaloneTopology struct {
Address string
}
StandaloneTopology configures single-node Redis access.
type StaticPasswordAuth ¶
type StaticPasswordAuth struct {
Password string
}
StaticPasswordAuth authenticates using a static password.
func (StaticPasswordAuth) GoString ¶ added in v2.3.0
func (a StaticPasswordAuth) GoString() string
GoString returns a redacted representation for fmt %#v.
func (StaticPasswordAuth) String ¶ added in v2.3.0
func (StaticPasswordAuth) String() string
String returns a redacted representation to prevent accidental credential logging.
type Status ¶
type Status struct {
Connected bool
LastRefreshError error
LastRefreshAt time.Time
RefreshLoopRunning bool
}
Status reports client connectivity and IAM refresh loop health.
type Topology ¶
type Topology struct {
Standalone *StandaloneTopology
Sentinel *SentinelTopology
Cluster *ClusterTopology
}
Topology selects exactly one Redis deployment mode.