blob: c89b3e5d7431cffcc32fa1ba88e9a7081503a686 [file] [log] [blame]
serkant.uluderyae5afeff2021-02-23 18:00:23 +03001package redis
2
3import (
4 "context"
5 "crypto/tls"
6 "net"
7 "time"
8)
9
10// UniversalOptions information is required by UniversalClient to establish
11// connections.
12type UniversalOptions struct {
13 // Either a single address or a seed list of host:port addresses
14 // of cluster/sentinel nodes.
15 Addrs []string
16
17 // Database to be selected after connecting to the server.
18 // Only single-node and failover clients.
19 DB int
20
21 // Common options.
22
23 Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
24 OnConnect func(ctx context.Context, cn *Conn) error
25
26 Username string
27 Password string
Abhay Kumar40252eb2025-10-13 13:25:53 +000028 SentinelUsername string
serkant.uluderyae5afeff2021-02-23 18:00:23 +030029 SentinelPassword string
30
31 MaxRetries int
32 MinRetryBackoff time.Duration
33 MaxRetryBackoff time.Duration
34
35 DialTimeout time.Duration
36 ReadTimeout time.Duration
37 WriteTimeout time.Duration
38
Abhay Kumar40252eb2025-10-13 13:25:53 +000039 // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
40 PoolFIFO bool
41
serkant.uluderyae5afeff2021-02-23 18:00:23 +030042 PoolSize int
43 MinIdleConns int
44 MaxConnAge time.Duration
45 PoolTimeout time.Duration
46 IdleTimeout time.Duration
47 IdleCheckFrequency time.Duration
48
49 TLSConfig *tls.Config
50
51 // Only cluster clients.
52
53 MaxRedirects int
54 ReadOnly bool
55 RouteByLatency bool
56 RouteRandomly bool
57
58 // The sentinel master name.
59 // Only failover clients.
Abhay Kumar40252eb2025-10-13 13:25:53 +000060
serkant.uluderyae5afeff2021-02-23 18:00:23 +030061 MasterName string
62}
63
64// Cluster returns cluster options created from the universal options.
65func (o *UniversalOptions) Cluster() *ClusterOptions {
66 if len(o.Addrs) == 0 {
67 o.Addrs = []string{"127.0.0.1:6379"}
68 }
69
70 return &ClusterOptions{
71 Addrs: o.Addrs,
72 Dialer: o.Dialer,
73 OnConnect: o.OnConnect,
74
75 Username: o.Username,
76 Password: o.Password,
77
78 MaxRedirects: o.MaxRedirects,
79 ReadOnly: o.ReadOnly,
80 RouteByLatency: o.RouteByLatency,
81 RouteRandomly: o.RouteRandomly,
82
83 MaxRetries: o.MaxRetries,
84 MinRetryBackoff: o.MinRetryBackoff,
85 MaxRetryBackoff: o.MaxRetryBackoff,
86
87 DialTimeout: o.DialTimeout,
88 ReadTimeout: o.ReadTimeout,
89 WriteTimeout: o.WriteTimeout,
Abhay Kumar40252eb2025-10-13 13:25:53 +000090 PoolFIFO: o.PoolFIFO,
serkant.uluderyae5afeff2021-02-23 18:00:23 +030091 PoolSize: o.PoolSize,
92 MinIdleConns: o.MinIdleConns,
93 MaxConnAge: o.MaxConnAge,
94 PoolTimeout: o.PoolTimeout,
95 IdleTimeout: o.IdleTimeout,
96 IdleCheckFrequency: o.IdleCheckFrequency,
97
98 TLSConfig: o.TLSConfig,
99 }
100}
101
102// Failover returns failover options created from the universal options.
103func (o *UniversalOptions) Failover() *FailoverOptions {
104 if len(o.Addrs) == 0 {
105 o.Addrs = []string{"127.0.0.1:26379"}
106 }
107
108 return &FailoverOptions{
109 SentinelAddrs: o.Addrs,
110 MasterName: o.MasterName,
111
112 Dialer: o.Dialer,
113 OnConnect: o.OnConnect,
114
115 DB: o.DB,
116 Username: o.Username,
117 Password: o.Password,
Abhay Kumar40252eb2025-10-13 13:25:53 +0000118 SentinelUsername: o.SentinelUsername,
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300119 SentinelPassword: o.SentinelPassword,
120
121 MaxRetries: o.MaxRetries,
122 MinRetryBackoff: o.MinRetryBackoff,
123 MaxRetryBackoff: o.MaxRetryBackoff,
124
125 DialTimeout: o.DialTimeout,
126 ReadTimeout: o.ReadTimeout,
127 WriteTimeout: o.WriteTimeout,
128
Abhay Kumar40252eb2025-10-13 13:25:53 +0000129 PoolFIFO: o.PoolFIFO,
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300130 PoolSize: o.PoolSize,
131 MinIdleConns: o.MinIdleConns,
132 MaxConnAge: o.MaxConnAge,
133 PoolTimeout: o.PoolTimeout,
134 IdleTimeout: o.IdleTimeout,
135 IdleCheckFrequency: o.IdleCheckFrequency,
136
137 TLSConfig: o.TLSConfig,
138 }
139}
140
141// Simple returns basic options created from the universal options.
142func (o *UniversalOptions) Simple() *Options {
143 addr := "127.0.0.1:6379"
144 if len(o.Addrs) > 0 {
145 addr = o.Addrs[0]
146 }
147
148 return &Options{
149 Addr: addr,
150 Dialer: o.Dialer,
151 OnConnect: o.OnConnect,
152
153 DB: o.DB,
154 Username: o.Username,
155 Password: o.Password,
156
157 MaxRetries: o.MaxRetries,
158 MinRetryBackoff: o.MinRetryBackoff,
159 MaxRetryBackoff: o.MaxRetryBackoff,
160
161 DialTimeout: o.DialTimeout,
162 ReadTimeout: o.ReadTimeout,
163 WriteTimeout: o.WriteTimeout,
164
Abhay Kumar40252eb2025-10-13 13:25:53 +0000165 PoolFIFO: o.PoolFIFO,
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300166 PoolSize: o.PoolSize,
167 MinIdleConns: o.MinIdleConns,
168 MaxConnAge: o.MaxConnAge,
169 PoolTimeout: o.PoolTimeout,
170 IdleTimeout: o.IdleTimeout,
171 IdleCheckFrequency: o.IdleCheckFrequency,
172
173 TLSConfig: o.TLSConfig,
174 }
175}
176
177// --------------------------------------------------------------------
178
179// UniversalClient is an abstract client which - based on the provided options -
Abhay Kumar40252eb2025-10-13 13:25:53 +0000180// represents either a ClusterClient, a FailoverClient, or a single-node Client.
181// This can be useful for testing cluster-specific applications locally or having different
182// clients in different environments.
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300183type UniversalClient interface {
184 Cmdable
185 Context() context.Context
186 AddHook(Hook)
187 Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
188 Do(ctx context.Context, args ...interface{}) *Cmd
189 Process(ctx context.Context, cmd Cmder) error
190 Subscribe(ctx context.Context, channels ...string) *PubSub
191 PSubscribe(ctx context.Context, channels ...string) *PubSub
192 Close() error
193 PoolStats() *PoolStats
194}
195
196var (
197 _ UniversalClient = (*Client)(nil)
198 _ UniversalClient = (*ClusterClient)(nil)
199 _ UniversalClient = (*Ring)(nil)
200)
201
Abhay Kumar40252eb2025-10-13 13:25:53 +0000202// NewUniversalClient returns a new multi client. The type of the returned client depends
203// on the following conditions:
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300204//
Abhay Kumar40252eb2025-10-13 13:25:53 +0000205// 1. If the MasterName option is specified, a sentinel-backed FailoverClient is returned.
206// 2. if the number of Addrs is two or more, a ClusterClient is returned.
207// 3. Otherwise, a single-node Client is returned.
serkant.uluderyae5afeff2021-02-23 18:00:23 +0300208func NewUniversalClient(opts *UniversalOptions) UniversalClient {
209 if opts.MasterName != "" {
210 return NewFailoverClient(opts.Failover())
211 } else if len(opts.Addrs) > 1 {
212 return NewClusterClient(opts.Cluster())
213 }
214 return NewClient(opts.Simple())
215}