blob: 5f0e1e33a5ef4947af66b16026b0fd56a03e2d55 [file] [log] [blame]
Joey Armstronge8c091f2023-01-17 16:56:26 -05001package 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
28 SentinelPassword string
29
30 MaxRetries int
31 MinRetryBackoff time.Duration
32 MaxRetryBackoff time.Duration
33
34 DialTimeout time.Duration
35 ReadTimeout time.Duration
36 WriteTimeout time.Duration
37
38 PoolSize int
39 MinIdleConns int
40 MaxConnAge time.Duration
41 PoolTimeout time.Duration
42 IdleTimeout time.Duration
43 IdleCheckFrequency time.Duration
44
45 TLSConfig *tls.Config
46
47 // Only cluster clients.
48
49 MaxRedirects int
50 ReadOnly bool
51 RouteByLatency bool
52 RouteRandomly bool
53
54 // The sentinel master name.
55 // Only failover clients.
56 MasterName string
57}
58
59// Cluster returns cluster options created from the universal options.
60func (o *UniversalOptions) Cluster() *ClusterOptions {
61 if len(o.Addrs) == 0 {
62 o.Addrs = []string{"127.0.0.1:6379"}
63 }
64
65 return &ClusterOptions{
66 Addrs: o.Addrs,
67 Dialer: o.Dialer,
68 OnConnect: o.OnConnect,
69
70 Username: o.Username,
71 Password: o.Password,
72
73 MaxRedirects: o.MaxRedirects,
74 ReadOnly: o.ReadOnly,
75 RouteByLatency: o.RouteByLatency,
76 RouteRandomly: o.RouteRandomly,
77
78 MaxRetries: o.MaxRetries,
79 MinRetryBackoff: o.MinRetryBackoff,
80 MaxRetryBackoff: o.MaxRetryBackoff,
81
82 DialTimeout: o.DialTimeout,
83 ReadTimeout: o.ReadTimeout,
84 WriteTimeout: o.WriteTimeout,
85 PoolSize: o.PoolSize,
86 MinIdleConns: o.MinIdleConns,
87 MaxConnAge: o.MaxConnAge,
88 PoolTimeout: o.PoolTimeout,
89 IdleTimeout: o.IdleTimeout,
90 IdleCheckFrequency: o.IdleCheckFrequency,
91
92 TLSConfig: o.TLSConfig,
93 }
94}
95
96// Failover returns failover options created from the universal options.
97func (o *UniversalOptions) Failover() *FailoverOptions {
98 if len(o.Addrs) == 0 {
99 o.Addrs = []string{"127.0.0.1:26379"}
100 }
101
102 return &FailoverOptions{
103 SentinelAddrs: o.Addrs,
104 MasterName: o.MasterName,
105
106 Dialer: o.Dialer,
107 OnConnect: o.OnConnect,
108
109 DB: o.DB,
110 Username: o.Username,
111 Password: o.Password,
112 SentinelPassword: o.SentinelPassword,
113
114 MaxRetries: o.MaxRetries,
115 MinRetryBackoff: o.MinRetryBackoff,
116 MaxRetryBackoff: o.MaxRetryBackoff,
117
118 DialTimeout: o.DialTimeout,
119 ReadTimeout: o.ReadTimeout,
120 WriteTimeout: o.WriteTimeout,
121
122 PoolSize: o.PoolSize,
123 MinIdleConns: o.MinIdleConns,
124 MaxConnAge: o.MaxConnAge,
125 PoolTimeout: o.PoolTimeout,
126 IdleTimeout: o.IdleTimeout,
127 IdleCheckFrequency: o.IdleCheckFrequency,
128
129 TLSConfig: o.TLSConfig,
130 }
131}
132
133// Simple returns basic options created from the universal options.
134func (o *UniversalOptions) Simple() *Options {
135 addr := "127.0.0.1:6379"
136 if len(o.Addrs) > 0 {
137 addr = o.Addrs[0]
138 }
139
140 return &Options{
141 Addr: addr,
142 Dialer: o.Dialer,
143 OnConnect: o.OnConnect,
144
145 DB: o.DB,
146 Username: o.Username,
147 Password: o.Password,
148
149 MaxRetries: o.MaxRetries,
150 MinRetryBackoff: o.MinRetryBackoff,
151 MaxRetryBackoff: o.MaxRetryBackoff,
152
153 DialTimeout: o.DialTimeout,
154 ReadTimeout: o.ReadTimeout,
155 WriteTimeout: o.WriteTimeout,
156
157 PoolSize: o.PoolSize,
158 MinIdleConns: o.MinIdleConns,
159 MaxConnAge: o.MaxConnAge,
160 PoolTimeout: o.PoolTimeout,
161 IdleTimeout: o.IdleTimeout,
162 IdleCheckFrequency: o.IdleCheckFrequency,
163
164 TLSConfig: o.TLSConfig,
165 }
166}
167
168// --------------------------------------------------------------------
169
170// UniversalClient is an abstract client which - based on the provided options -
171// can connect to either clusters, or sentinel-backed failover instances
172// or simple single-instance servers. This can be useful for testing
173// cluster-specific applications locally.
174type UniversalClient interface {
175 Cmdable
176 Context() context.Context
177 AddHook(Hook)
178 Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
179 Do(ctx context.Context, args ...interface{}) *Cmd
180 Process(ctx context.Context, cmd Cmder) error
181 Subscribe(ctx context.Context, channels ...string) *PubSub
182 PSubscribe(ctx context.Context, channels ...string) *PubSub
183 Close() error
184 PoolStats() *PoolStats
185}
186
187var (
188 _ UniversalClient = (*Client)(nil)
189 _ UniversalClient = (*ClusterClient)(nil)
190 _ UniversalClient = (*Ring)(nil)
191)
192
193// NewUniversalClient returns a new multi client. The type of client returned depends
194// on the following three conditions:
195//
196// 1. if a MasterName is passed a sentinel-backed FailoverClient will be returned
197// 2. if the number of Addrs is two or more, a ClusterClient will be returned
198// 3. otherwise, a single-node redis Client will be returned.
199func NewUniversalClient(opts *UniversalOptions) UniversalClient {
200 if opts.MasterName != "" {
201 return NewFailoverClient(opts.Failover())
202 } else if len(opts.Addrs) > 1 {
203 return NewClusterClient(opts.Cluster())
204 }
205 return NewClient(opts.Simple())
206}