mirror of
https://github.com/redis/go-redis.git
synced 2025-07-22 10:01:50 +03:00
874 lines
21 KiB
Markdown
874 lines
21 KiB
Markdown
# Redis Client Architecture
|
|
|
|
This document explains the relationships between different components of the Redis client implementation, focusing on client types, connections, pools, and hooks.
|
|
|
|
## Client Hierarchy
|
|
|
|
### Component Relationships
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class baseClient {
|
|
+*Options opt
|
|
+pool.Pooler connPool
|
|
+hooksMixin
|
|
+onClose func() error
|
|
+clone() *baseClient
|
|
+initConn()
|
|
+process()
|
|
}
|
|
|
|
class Client {
|
|
+baseClient
|
|
+cmdable
|
|
+hooksMixin
|
|
+NewClient()
|
|
+WithTimeout()
|
|
+Pipeline()
|
|
+TxPipeline()
|
|
}
|
|
|
|
class Conn {
|
|
+baseClient
|
|
+cmdable
|
|
+statefulCmdable
|
|
+hooksMixin
|
|
+newConn()
|
|
}
|
|
|
|
class Pipeline {
|
|
+exec pipelineExecer
|
|
+init()
|
|
+Pipelined()
|
|
}
|
|
|
|
class TxPipeline {
|
|
+Pipeline
|
|
+wrapMultiExec()
|
|
}
|
|
|
|
class hooksMixin {
|
|
+*sync.RWMutex hooksMu
|
|
+[]Hook slice
|
|
+hooks initial
|
|
+hooks current
|
|
+clone() hooksMixin
|
|
+AddHook()
|
|
+chain()
|
|
}
|
|
|
|
Client --> baseClient : embeds
|
|
Conn --> baseClient : embeds
|
|
Pipeline --> Client : uses
|
|
TxPipeline --> Pipeline : extends
|
|
baseClient --> hooksMixin : contains
|
|
Client --> hooksMixin : contains
|
|
Conn --> hooksMixin : contains
|
|
```
|
|
|
|
### Hook Chain Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Hook1
|
|
participant Hook2
|
|
participant Redis
|
|
|
|
Client->>Hook1: Execute Command
|
|
Hook1->>Hook2: Next Hook
|
|
Hook2->>Redis: Execute Command
|
|
Redis-->>Hook2: Response
|
|
Hook2-->>Hook1: Process Response
|
|
Hook1-->>Client: Final Response
|
|
```
|
|
|
|
### Connection Pool Management
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Idle
|
|
Idle --> InUse: Get Connection
|
|
InUse --> Idle: Release Connection
|
|
InUse --> Closed: Connection Error
|
|
Idle --> Closed: Pool Shutdown
|
|
Closed --> [*]
|
|
```
|
|
|
|
### Pipeline Execution Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Pipeline
|
|
participant Redis
|
|
|
|
Client->>Pipeline: Queue Command 1
|
|
Client->>Pipeline: Queue Command 2
|
|
Client->>Pipeline: Queue Command 3
|
|
Pipeline->>Redis: Send Batch
|
|
Redis-->>Pipeline: Batch Response
|
|
Pipeline-->>Client: Processed Responses
|
|
```
|
|
|
|
### Transaction Pipeline Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant TxPipeline
|
|
participant Redis
|
|
|
|
Client->>TxPipeline: Queue Command 1
|
|
Client->>TxPipeline: Queue Command 2
|
|
TxPipeline->>Redis: MULTI
|
|
TxPipeline->>Redis: Command 1
|
|
TxPipeline->>Redis: Command 2
|
|
TxPipeline->>Redis: EXEC
|
|
Redis-->>TxPipeline: Transaction Result
|
|
TxPipeline-->>Client: Processed Results
|
|
```
|
|
|
|
### Base Client (`baseClient`)
|
|
|
|
The `baseClient` is the foundation of all Redis client implementations. It contains:
|
|
- Connection pool management
|
|
- Basic Redis command execution
|
|
- Hook management
|
|
- Connection lifecycle handling
|
|
|
|
```go
|
|
type baseClient struct {
|
|
opt *Options
|
|
connPool pool.Pooler
|
|
hooksMixin
|
|
onClose func() error
|
|
}
|
|
```
|
|
|
|
### Client Types
|
|
|
|
1. **Client (`Client`)**
|
|
- The main Redis client used by applications
|
|
- Represents a pool of connections
|
|
- Safe for concurrent use
|
|
- Embeds `baseClient` and adds command execution capabilities
|
|
- Primary entry point for most Redis operations
|
|
- Handles connection pooling and retries automatically
|
|
|
|
2. **Conn (`Conn`)**
|
|
- Represents a single Redis connection
|
|
- Used for stateful operations like pub/sub
|
|
- Required for blocking operations (BLPOP, BRPOP)
|
|
- Also embeds `baseClient`
|
|
- Has additional stateful command capabilities
|
|
- Not safe for concurrent use
|
|
|
|
3. **Pipeline (`Pipeline`)**
|
|
- Used for pipelining multiple commands
|
|
- Not a standalone client, but a wrapper around existing clients
|
|
- Batches commands and sends them in a single network roundtrip
|
|
|
|
4. **Transaction Pipeline (`TxPipeline`)**
|
|
- Similar to Pipeline but wraps commands in MULTI/EXEC
|
|
- Ensures atomic execution of commands
|
|
- Also a wrapper around existing clients
|
|
|
|
## Pointer vs Value Semantics
|
|
|
|
### When `baseClient` is a Pointer
|
|
|
|
The `baseClient` is used as a pointer in these scenarios:
|
|
|
|
1. **Client Creation**
|
|
```go
|
|
func NewClient(opt *Options) *Client {
|
|
c := Client{
|
|
baseClient: &baseClient{
|
|
opt: opt,
|
|
},
|
|
}
|
|
}
|
|
```
|
|
- Used as pointer to share the same base client instance
|
|
- Allows modifications to propagate to all references
|
|
- More efficient for large structs
|
|
|
|
2. **Connection Pooling**
|
|
- Pooled connections need to share the same base client configuration
|
|
- Pointer semantics ensure consistent behavior across pooled connections
|
|
|
|
### When `baseClient` is a Value
|
|
|
|
The `baseClient` is used as a value in these scenarios:
|
|
|
|
1. **Cloning**
|
|
```go
|
|
func (c *baseClient) clone() *baseClient {
|
|
clone := *c
|
|
clone.hooksMixin = c.hooksMixin.clone()
|
|
return &clone
|
|
}
|
|
```
|
|
- Creates independent copies for isolation
|
|
- Prevents unintended sharing of state
|
|
- Used when creating new connections or client instances
|
|
|
|
2. **Temporary Operations**
|
|
- When creating short-lived client instances
|
|
- When isolation is required for specific operations
|
|
|
|
## Hooks Management
|
|
|
|
### HooksMixin
|
|
|
|
The `hooksMixin` is a struct that manages hook chains for different operations:
|
|
|
|
```go
|
|
type hooksMixin struct {
|
|
hooksMu *sync.RWMutex
|
|
slice []Hook
|
|
initial hooks
|
|
current hooks
|
|
}
|
|
```
|
|
|
|
### Hook Types
|
|
|
|
1. **Dial Hook**
|
|
- Called during connection establishment
|
|
- Can modify connection parameters
|
|
- Used for custom connection handling
|
|
|
|
2. **Process Hook**
|
|
- Called before command execution
|
|
- Can modify commands or add logging
|
|
- Used for command monitoring
|
|
|
|
3. **Pipeline Hook**
|
|
- Called during pipeline execution
|
|
- Handles batch command processing
|
|
- Used for pipeline monitoring
|
|
|
|
### Hook Lifecycle
|
|
|
|
1. **Initialization**
|
|
- Hooks are initialized when creating a new client
|
|
- Default hooks are set up for basic operations
|
|
- Hooks can be added or removed at runtime
|
|
|
|
2. **Hook Chain**
|
|
- Hooks are chained in LIFO (Last In, First Out) order
|
|
- Each hook can modify the command or response
|
|
- Chain can be modified at runtime
|
|
- Hooks can prevent command execution by not calling next
|
|
|
|
3. **Hook Inheritance**
|
|
- New connections inherit hooks from their parent client
|
|
- Hooks are cloned to prevent shared state
|
|
- Each connection maintains its own hook chain
|
|
- Hook modifications in child don't affect parent
|
|
|
|
## Connection Pooling
|
|
|
|
### Pool Types
|
|
|
|
1. **Single Connection Pool**
|
|
- Used for dedicated connections
|
|
- No connection sharing
|
|
- Used in `Conn` type
|
|
|
|
2. **Multi Connection Pool**
|
|
- Used for client pools
|
|
- Manages multiple connections
|
|
- Handles connection reuse
|
|
|
|
### Pool Management
|
|
|
|
1. **Connection Acquisition**
|
|
- Connections are acquired from the pool
|
|
- Pool maintains minimum and maximum connections
|
|
- Handles connection timeouts
|
|
|
|
2. **Connection Release**
|
|
- Connections are returned to the pool
|
|
- Pool handles connection cleanup
|
|
- Manages connection lifecycle
|
|
|
|
### Pool Configuration
|
|
|
|
1. **Pool Options**
|
|
- Minimum idle connections
|
|
- Maximum active connections
|
|
- Connection idle timeout
|
|
- Connection lifetime
|
|
- Pool health check interval
|
|
|
|
2. **Health Checks**
|
|
- Periodic connection validation
|
|
- Automatic reconnection on failure
|
|
- Connection cleanup on errors
|
|
- Pool size maintenance
|
|
|
|
## Transaction and Pipeline Handling
|
|
|
|
### Pipeline
|
|
|
|
1. **Command Batching**
|
|
- Commands are queued in memory
|
|
- Sent in a single network roundtrip
|
|
- Responses are collected in order
|
|
|
|
2. **Error Handling**
|
|
- Pipeline execution is atomic
|
|
- Errors are propagated to all commands
|
|
- Connection errors trigger retries
|
|
|
|
### Transaction Pipeline
|
|
|
|
1. **MULTI/EXEC Wrapping**
|
|
- Commands are wrapped in MULTI/EXEC
|
|
- Ensures atomic execution
|
|
- Handles transaction errors
|
|
|
|
2. **State Management**
|
|
- Maintains transaction state
|
|
- Handles rollback scenarios
|
|
- Manages connection state
|
|
|
|
### Pipeline Limitations
|
|
|
|
1. **Size Limits**
|
|
- Maximum commands per pipeline
|
|
- Memory usage considerations
|
|
- Network buffer size limits
|
|
- Response size handling
|
|
|
|
2. **Transaction Behavior**
|
|
- WATCH/UNWATCH key monitoring
|
|
- Transaction isolation
|
|
- Rollback on failure
|
|
- Atomic execution guarantees
|
|
|
|
## Error Handling and Cleanup
|
|
|
|
### Error Types and Handling
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class Error {
|
|
<<interface>>
|
|
+Error() string
|
|
}
|
|
|
|
class RedisError {
|
|
+string message
|
|
+Error() string
|
|
}
|
|
|
|
class ConnectionError {
|
|
+string message
|
|
+net.Error
|
|
+Temporary() bool
|
|
+Timeout() bool
|
|
}
|
|
|
|
class TxFailedError {
|
|
+string message
|
|
+Error() string
|
|
}
|
|
|
|
Error <|-- RedisError
|
|
Error <|-- ConnectionError
|
|
Error <|-- TxFailedError
|
|
net.Error <|-- ConnectionError
|
|
```
|
|
|
|
### Error Handling Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Connection
|
|
participant Redis
|
|
participant ErrorHandler
|
|
|
|
Client->>Connection: Execute Command
|
|
Connection->>Redis: Send Command
|
|
alt Connection Error
|
|
Redis-->>Connection: Connection Error
|
|
Connection->>ErrorHandler: Handle Connection Error
|
|
ErrorHandler->>Connection: Retry or Close
|
|
else Redis Error
|
|
Redis-->>Connection: Redis Error
|
|
Connection->>Client: Return Error
|
|
else Transaction Error
|
|
Redis-->>Connection: Transaction Failed
|
|
Connection->>Client: Return TxFailedError
|
|
end
|
|
```
|
|
|
|
### Connection and Client Cleanup
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Client
|
|
participant ConnectionPool
|
|
participant Connection
|
|
participant Hook
|
|
|
|
User->>Client: Close()
|
|
Client->>Hook: Execute Close Hooks
|
|
Hook-->>Client: Hook Complete
|
|
Client->>ConnectionPool: Close All Connections
|
|
ConnectionPool->>Connection: Close
|
|
Connection->>Redis: Close Connection
|
|
Redis-->>Connection: Connection Closed
|
|
Connection-->>ConnectionPool: Connection Removed
|
|
ConnectionPool-->>Client: Pool Closed
|
|
Client-->>User: Client Closed
|
|
```
|
|
|
|
### Error Handling Strategies
|
|
|
|
1. **Connection Errors**
|
|
- Temporary errors (network issues) trigger retries
|
|
- Permanent errors (invalid credentials) close the connection
|
|
- Connection pool handles reconnection attempts
|
|
- Maximum retry attempts configurable via options
|
|
|
|
2. **Redis Errors**
|
|
- Command-specific errors returned to caller
|
|
- No automatic retries for Redis errors
|
|
- Error types include:
|
|
- Command syntax errors
|
|
- Type errors
|
|
- Permission errors
|
|
- Resource limit errors
|
|
|
|
3. **Transaction Errors**
|
|
- MULTI/EXEC failures return `TxFailedError`
|
|
- Individual command errors within transaction
|
|
- Watch/Unwatch failures
|
|
- Connection errors during transaction
|
|
|
|
### Cleanup Process
|
|
|
|
1. **Client Cleanup**
|
|
```go
|
|
func (c *Client) Close() error {
|
|
// Execute close hooks
|
|
if c.onClose != nil {
|
|
c.onClose()
|
|
}
|
|
// Close connection pool
|
|
return c.connPool.Close()
|
|
}
|
|
```
|
|
- Executes registered close hooks
|
|
- Closes all connections in pool
|
|
- Releases all resources
|
|
- Thread-safe operation
|
|
|
|
2. **Connection Cleanup**
|
|
```go
|
|
func (c *Conn) Close() error {
|
|
// Cleanup connection state
|
|
c.state = closed
|
|
// Close underlying connection
|
|
return c.conn.Close()
|
|
}
|
|
```
|
|
- Closes underlying network connection
|
|
- Cleans up connection state
|
|
- Removes from connection pool
|
|
- Handles pending operations
|
|
|
|
3. **Pool Cleanup**
|
|
- Closes all idle connections
|
|
- Waits for in-use connections
|
|
- Handles connection timeouts
|
|
- Releases pool resources
|
|
|
|
### Best Practices for Error Handling
|
|
|
|
1. **Connection Management**
|
|
- Always check for connection errors
|
|
- Implement proper retry logic
|
|
- Handle connection timeouts
|
|
- Monitor connection pool health
|
|
|
|
2. **Resource Cleanup**
|
|
- Always call Close() when done
|
|
- Use defer for cleanup in critical sections
|
|
- Handle cleanup errors
|
|
- Monitor resource usage
|
|
|
|
3. **Error Recovery**
|
|
- Implement circuit breakers
|
|
- Use backoff strategies
|
|
- Monitor error patterns
|
|
- Log error details
|
|
|
|
4. **Transaction Safety**
|
|
- Check transaction results
|
|
- Handle watch/unwatch failures
|
|
- Implement rollback strategies
|
|
- Monitor transaction timeouts
|
|
|
|
### Context and Cancellation
|
|
|
|
1. **Context Usage**
|
|
- Command execution timeout
|
|
- Connection establishment timeout
|
|
- Operation cancellation
|
|
- Resource cleanup on cancellation
|
|
|
|
2. **Pool Error Handling**
|
|
- Connection acquisition timeout
|
|
- Pool exhaustion handling
|
|
- Connection validation errors
|
|
- Resource cleanup on errors
|
|
|
|
## Best Practices
|
|
|
|
1. **Client Usage**
|
|
- Use `Client` for most operations
|
|
- Use `Conn` for stateful operations
|
|
- Use pipelines for batch operations
|
|
|
|
2. **Hook Implementation**
|
|
- Keep hooks lightweight
|
|
- Handle errors properly
|
|
- Call next hook in chain
|
|
|
|
3. **Connection Management**
|
|
- Let the pool handle connections
|
|
- Don't manually manage connections
|
|
- Use appropriate timeouts
|
|
|
|
4. **Error Handling**
|
|
- Check command errors
|
|
- Handle connection errors
|
|
- Implement retry logic when needed
|
|
|
|
## Deep Dive: baseClient Embedding Strategies
|
|
|
|
### Implementation Examples
|
|
|
|
1. **Client Implementation (Pointer Embedding)**
|
|
```go
|
|
type Client struct {
|
|
*baseClient // Pointer embedding
|
|
cmdable
|
|
hooksMixin
|
|
}
|
|
|
|
func NewClient(opt *Options) *Client {
|
|
c := Client{
|
|
baseClient: &baseClient{ // Created as pointer
|
|
opt: opt,
|
|
},
|
|
}
|
|
c.init()
|
|
c.connPool = newConnPool(opt, c.dialHook)
|
|
return &c
|
|
}
|
|
```
|
|
The `Client` uses pointer embedding because:
|
|
- It needs to share the same `baseClient` instance across all operations
|
|
- The `baseClient` contains connection pool and options that should be shared
|
|
- Modifications to the base client (like timeouts) should affect all operations
|
|
- More efficient for large structs since it avoids copying
|
|
|
|
2. **Conn Implementation (Value Embedding)**
|
|
```go
|
|
type Conn struct {
|
|
baseClient // Value embedding
|
|
cmdable
|
|
statefulCmdable
|
|
hooksMixin
|
|
}
|
|
|
|
func newConn(opt *Options, connPool pool.Pooler, parentHooks hooksMixin) *Conn {
|
|
c := Conn{
|
|
baseClient: baseClient{ // Created as value
|
|
opt: opt,
|
|
connPool: connPool,
|
|
},
|
|
}
|
|
c.cmdable = c.Process
|
|
c.statefulCmdable = c.Process
|
|
c.hooksMixin = parentHooks.clone()
|
|
return &c
|
|
}
|
|
```
|
|
The `Conn` uses value embedding because:
|
|
- Each connection needs its own independent state
|
|
- Connections are short-lived and don't need to share state
|
|
- Prevents unintended sharing of connection state
|
|
- More memory efficient for single connections
|
|
|
|
3. **Tx (Transaction) Implementation (Value Embedding)**
|
|
```go
|
|
type Tx struct {
|
|
baseClient // Value embedding
|
|
cmdable
|
|
statefulCmdable
|
|
hooksMixin
|
|
}
|
|
|
|
func (c *Client) newTx() *Tx {
|
|
tx := Tx{
|
|
baseClient: baseClient{ // Created as value
|
|
opt: c.opt,
|
|
connPool: pool.NewStickyConnPool(c.connPool),
|
|
},
|
|
hooksMixin: c.hooksMixin.clone(),
|
|
}
|
|
tx.init()
|
|
return &tx
|
|
}
|
|
```
|
|
The `Tx` uses value embedding because:
|
|
- Transactions need isolated state
|
|
- Each transaction has its own connection pool
|
|
- Prevents transaction state from affecting other operations
|
|
- Ensures atomic execution of commands
|
|
|
|
4. **Pipeline Implementation (No baseClient)**
|
|
```go
|
|
type Pipeline struct {
|
|
cmdable
|
|
statefulCmdable
|
|
exec pipelineExecer
|
|
cmds []Cmder
|
|
}
|
|
```
|
|
The `Pipeline` doesn't embed `baseClient` because:
|
|
- It's a temporary command buffer
|
|
- Doesn't need its own connection management
|
|
- Uses the parent client's connection pool
|
|
- More lightweight without base client overhead
|
|
|
|
### Embedding Strategy Comparison
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class Client {
|
|
+*baseClient
|
|
+cmdable
|
|
+hooksMixin
|
|
+NewClient()
|
|
+WithTimeout()
|
|
}
|
|
|
|
class Conn {
|
|
+baseClient
|
|
+cmdable
|
|
+statefulCmdable
|
|
+hooksMixin
|
|
+newConn()
|
|
}
|
|
|
|
class Tx {
|
|
+baseClient
|
|
+cmdable
|
|
+statefulCmdable
|
|
+hooksMixin
|
|
+newTx()
|
|
}
|
|
|
|
class Pipeline {
|
|
+cmdable
|
|
+statefulCmdable
|
|
+exec pipelineExecer
|
|
+cmds []Cmder
|
|
}
|
|
|
|
Client --> baseClient : pointer
|
|
Conn --> baseClient : value
|
|
Tx --> baseClient : value
|
|
Pipeline --> baseClient : none
|
|
```
|
|
|
|
### Key Differences in Embedding Strategy
|
|
|
|
1. **Pointer Embedding (Client)**
|
|
- Used when state needs to be shared
|
|
- More efficient for large structs
|
|
- Allows modifications to propagate
|
|
- Better for long-lived instances
|
|
- Memory Layout:
|
|
```
|
|
+-------------------+
|
|
| Client |
|
|
| +-------------+ |
|
|
| | *baseClient | |
|
|
| +-------------+ |
|
|
| | cmdable | |
|
|
| +-------------+ |
|
|
| | hooksMixin | |
|
|
| +-------------+ |
|
|
+-------------------+
|
|
```
|
|
|
|
2. **Value Embedding (Conn, Tx)**
|
|
- Used when isolation is needed
|
|
- Prevents unintended state sharing
|
|
- Better for short-lived instances
|
|
- More memory efficient for small instances
|
|
- Memory Layout:
|
|
```
|
|
+-------------------+
|
|
| Conn/Tx |
|
|
| +-------------+ |
|
|
| | baseClient | |
|
|
| | +---------+ | |
|
|
| | | Options | | |
|
|
| | +---------+ | |
|
|
| | | Pooler | | |
|
|
| | +---------+ | |
|
|
| +-------------+ |
|
|
| | cmdable | |
|
|
| +-------------+ |
|
|
| | hooksMixin | |
|
|
| +-------------+ |
|
|
+-------------------+
|
|
```
|
|
|
|
3. **No Embedding (Pipeline)**
|
|
- Used for temporary operations
|
|
- Minimizes memory overhead
|
|
- Relies on parent client
|
|
- Better for command batching
|
|
- Memory Layout:
|
|
```
|
|
+-------------------+
|
|
| Pipeline |
|
|
| +-------------+ |
|
|
| | cmdable | |
|
|
| +-------------+ |
|
|
| | exec | |
|
|
| +-------------+ |
|
|
| | cmds | |
|
|
| +-------------+ |
|
|
+-------------------+
|
|
```
|
|
|
|
### Design Implications
|
|
|
|
1. **Resource Management**
|
|
- Pointer embedding enables shared resource management
|
|
- Value embedding ensures resource isolation
|
|
- No embedding minimizes resource overhead
|
|
|
|
2. **State Management**
|
|
- Pointer embedding allows state propagation
|
|
- Value embedding prevents state leakage
|
|
- No embedding avoids state management
|
|
|
|
3. **Performance Considerations**
|
|
- Pointer embedding reduces memory usage for large structs
|
|
- Value embedding improves locality for small structs
|
|
- No embedding minimizes memory footprint
|
|
|
|
4. **Error Handling**
|
|
- Pointer embedding centralizes error handling
|
|
- Value embedding isolates error effects
|
|
- No embedding delegates error handling
|
|
|
|
5. **Cleanup Process**
|
|
- Pointer embedding requires coordinated cleanup
|
|
- Value embedding enables independent cleanup
|
|
- No embedding avoids cleanup complexity
|
|
|
|
### Best Practices
|
|
|
|
1. **When to Use Pointer Embedding**
|
|
- Long-lived instances
|
|
- Shared state requirements
|
|
- Large structs
|
|
- Centralized management
|
|
|
|
2. **When to Use Value Embedding**
|
|
- Short-lived instances
|
|
- State isolation needs
|
|
- Small structs
|
|
- Independent management
|
|
|
|
3. **When to Avoid Embedding**
|
|
- Temporary operations
|
|
- Minimal state needs
|
|
- Command batching
|
|
- Performance critical paths
|
|
|
|
### Authentication System
|
|
|
|
#### Streaming Credentials Provider
|
|
The Redis client supports a streaming credentials provider system that allows for dynamic credential updates:
|
|
|
|
```go
|
|
type StreamingCredentialsProvider interface {
|
|
Subscribe(listener CredentialsListener) (Credentials, UnsubscribeFunc, error)
|
|
}
|
|
|
|
type CredentialsListener interface {
|
|
OnNext(credentials Credentials)
|
|
OnError(err error)
|
|
}
|
|
|
|
type Credentials interface {
|
|
BasicAuth() (username string, password string)
|
|
RawCredentials() string
|
|
}
|
|
```
|
|
|
|
Key Features:
|
|
- Dynamic credential updates
|
|
- Error handling and propagation
|
|
- Basic authentication support
|
|
- Raw credential access
|
|
- Subscription management
|
|
|
|
#### Re-Authentication Listener
|
|
The client includes a re-authentication listener for handling credential updates:
|
|
|
|
```go
|
|
type ReAuthCredentialsListener struct {
|
|
reAuth func(credentials Credentials) error
|
|
onErr func(err error)
|
|
}
|
|
```
|
|
|
|
Features:
|
|
- Automatic re-authentication on credential updates
|
|
- Error handling and propagation
|
|
- Customizable re-authentication logic
|
|
- Thread-safe operation
|
|
|
|
#### Basic Authentication
|
|
The client provides a basic authentication implementation:
|
|
|
|
```go
|
|
type basicAuth struct {
|
|
username string
|
|
password string
|
|
}
|
|
|
|
func NewBasicCredentials(username, password string) Credentials {
|
|
return &basicAuth{
|
|
username: username,
|
|
password: password,
|
|
}
|
|
}
|
|
```
|
|
|
|
Usage:
|
|
- Simple username/password authentication
|
|
- Raw credential string generation
|
|
- Basic authentication support
|
|
- Thread-safe operation
|
|
|
|
// ... rest of existing content ... |