You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

352 lines
11 KiB

  1. package redis
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "net"
  6. "time"
  7. "github.com/redis/go-redis/v9/auth"
  8. "github.com/redis/go-redis/v9/maintnotifications"
  9. )
  10. // UniversalOptions information is required by UniversalClient to establish
  11. // connections.
  12. type UniversalOptions struct {
  13. // Either a single address or a seed list of host:port addresses
  14. // of cluster/sentinel nodes.
  15. Addrs []string
  16. // ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
  17. ClientName string
  18. // Database to be selected after connecting to the server.
  19. // Only single-node and failover clients.
  20. DB int
  21. // Common options.
  22. Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
  23. OnConnect func(ctx context.Context, cn *Conn) error
  24. Protocol int
  25. Username string
  26. Password string
  27. // CredentialsProvider allows the username and password to be updated
  28. // before reconnecting. It should return the current username and password.
  29. CredentialsProvider func() (username string, password string)
  30. // CredentialsProviderContext is an enhanced parameter of CredentialsProvider,
  31. // done to maintain API compatibility. In the future,
  32. // there might be a merge between CredentialsProviderContext and CredentialsProvider.
  33. // There will be a conflict between them; if CredentialsProviderContext exists, we will ignore CredentialsProvider.
  34. CredentialsProviderContext func(ctx context.Context) (username string, password string, err error)
  35. // StreamingCredentialsProvider is used to retrieve the credentials
  36. // for the connection from an external source. Those credentials may change
  37. // during the connection lifetime. This is useful for managed identity
  38. // scenarios where the credentials are retrieved from an external source.
  39. //
  40. // Currently, this is a placeholder for the future implementation.
  41. StreamingCredentialsProvider auth.StreamingCredentialsProvider
  42. SentinelUsername string
  43. SentinelPassword string
  44. MaxRetries int
  45. MinRetryBackoff time.Duration
  46. MaxRetryBackoff time.Duration
  47. DialTimeout time.Duration
  48. ReadTimeout time.Duration
  49. WriteTimeout time.Duration
  50. ContextTimeoutEnabled bool
  51. // ReadBufferSize is the size of the bufio.Reader buffer for each connection.
  52. // Larger buffers can improve performance for commands that return large responses.
  53. // Smaller buffers can improve memory usage for larger pools.
  54. //
  55. // default: 32KiB (32768 bytes)
  56. ReadBufferSize int
  57. // WriteBufferSize is the size of the bufio.Writer buffer for each connection.
  58. // Larger buffers can improve performance for large pipelines and commands with many arguments.
  59. // Smaller buffers can improve memory usage for larger pools.
  60. //
  61. // default: 32KiB (32768 bytes)
  62. WriteBufferSize int
  63. // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
  64. PoolFIFO bool
  65. PoolSize int
  66. PoolTimeout time.Duration
  67. MinIdleConns int
  68. MaxIdleConns int
  69. MaxActiveConns int
  70. ConnMaxIdleTime time.Duration
  71. ConnMaxLifetime time.Duration
  72. TLSConfig *tls.Config
  73. // Only cluster clients.
  74. MaxRedirects int
  75. ReadOnly bool
  76. RouteByLatency bool
  77. RouteRandomly bool
  78. // MasterName is the sentinel master name.
  79. // Only for failover clients.
  80. MasterName string
  81. // DisableIndentity - Disable set-lib on connect.
  82. //
  83. // default: false
  84. //
  85. // Deprecated: Use DisableIdentity instead.
  86. DisableIndentity bool
  87. // DisableIdentity is used to disable CLIENT SETINFO command on connect.
  88. //
  89. // default: false
  90. DisableIdentity bool
  91. IdentitySuffix string
  92. // FailingTimeoutSeconds is the timeout in seconds for marking a cluster node as failing.
  93. // When a node is marked as failing, it will be avoided for this duration.
  94. // Only applies to cluster clients. Default is 15 seconds.
  95. FailingTimeoutSeconds int
  96. UnstableResp3 bool
  97. // IsClusterMode can be used when only one Addrs is provided (e.g. Elasticache supports setting up cluster mode with configuration endpoint).
  98. IsClusterMode bool
  99. // MaintNotificationsConfig provides configuration for maintnotifications upgrades.
  100. MaintNotificationsConfig *maintnotifications.Config
  101. }
  102. // Cluster returns cluster options created from the universal options.
  103. func (o *UniversalOptions) Cluster() *ClusterOptions {
  104. if len(o.Addrs) == 0 {
  105. o.Addrs = []string{"127.0.0.1:6379"}
  106. }
  107. return &ClusterOptions{
  108. Addrs: o.Addrs,
  109. ClientName: o.ClientName,
  110. Dialer: o.Dialer,
  111. OnConnect: o.OnConnect,
  112. Protocol: o.Protocol,
  113. Username: o.Username,
  114. Password: o.Password,
  115. CredentialsProvider: o.CredentialsProvider,
  116. CredentialsProviderContext: o.CredentialsProviderContext,
  117. StreamingCredentialsProvider: o.StreamingCredentialsProvider,
  118. MaxRedirects: o.MaxRedirects,
  119. ReadOnly: o.ReadOnly,
  120. RouteByLatency: o.RouteByLatency,
  121. RouteRandomly: o.RouteRandomly,
  122. MaxRetries: o.MaxRetries,
  123. MinRetryBackoff: o.MinRetryBackoff,
  124. MaxRetryBackoff: o.MaxRetryBackoff,
  125. DialTimeout: o.DialTimeout,
  126. ReadTimeout: o.ReadTimeout,
  127. WriteTimeout: o.WriteTimeout,
  128. ContextTimeoutEnabled: o.ContextTimeoutEnabled,
  129. ReadBufferSize: o.ReadBufferSize,
  130. WriteBufferSize: o.WriteBufferSize,
  131. PoolFIFO: o.PoolFIFO,
  132. PoolSize: o.PoolSize,
  133. PoolTimeout: o.PoolTimeout,
  134. MinIdleConns: o.MinIdleConns,
  135. MaxIdleConns: o.MaxIdleConns,
  136. MaxActiveConns: o.MaxActiveConns,
  137. ConnMaxIdleTime: o.ConnMaxIdleTime,
  138. ConnMaxLifetime: o.ConnMaxLifetime,
  139. TLSConfig: o.TLSConfig,
  140. DisableIdentity: o.DisableIdentity,
  141. DisableIndentity: o.DisableIndentity,
  142. IdentitySuffix: o.IdentitySuffix,
  143. FailingTimeoutSeconds: o.FailingTimeoutSeconds,
  144. UnstableResp3: o.UnstableResp3,
  145. MaintNotificationsConfig: o.MaintNotificationsConfig,
  146. }
  147. }
  148. // Failover returns failover options created from the universal options.
  149. func (o *UniversalOptions) Failover() *FailoverOptions {
  150. if len(o.Addrs) == 0 {
  151. o.Addrs = []string{"127.0.0.1:26379"}
  152. }
  153. return &FailoverOptions{
  154. SentinelAddrs: o.Addrs,
  155. MasterName: o.MasterName,
  156. ClientName: o.ClientName,
  157. Dialer: o.Dialer,
  158. OnConnect: o.OnConnect,
  159. DB: o.DB,
  160. Protocol: o.Protocol,
  161. Username: o.Username,
  162. Password: o.Password,
  163. CredentialsProvider: o.CredentialsProvider,
  164. CredentialsProviderContext: o.CredentialsProviderContext,
  165. StreamingCredentialsProvider: o.StreamingCredentialsProvider,
  166. SentinelUsername: o.SentinelUsername,
  167. SentinelPassword: o.SentinelPassword,
  168. RouteByLatency: o.RouteByLatency,
  169. RouteRandomly: o.RouteRandomly,
  170. MaxRetries: o.MaxRetries,
  171. MinRetryBackoff: o.MinRetryBackoff,
  172. MaxRetryBackoff: o.MaxRetryBackoff,
  173. DialTimeout: o.DialTimeout,
  174. ReadTimeout: o.ReadTimeout,
  175. WriteTimeout: o.WriteTimeout,
  176. ContextTimeoutEnabled: o.ContextTimeoutEnabled,
  177. ReadBufferSize: o.ReadBufferSize,
  178. WriteBufferSize: o.WriteBufferSize,
  179. PoolFIFO: o.PoolFIFO,
  180. PoolSize: o.PoolSize,
  181. PoolTimeout: o.PoolTimeout,
  182. MinIdleConns: o.MinIdleConns,
  183. MaxIdleConns: o.MaxIdleConns,
  184. MaxActiveConns: o.MaxActiveConns,
  185. ConnMaxIdleTime: o.ConnMaxIdleTime,
  186. ConnMaxLifetime: o.ConnMaxLifetime,
  187. TLSConfig: o.TLSConfig,
  188. ReplicaOnly: o.ReadOnly,
  189. DisableIdentity: o.DisableIdentity,
  190. DisableIndentity: o.DisableIndentity,
  191. IdentitySuffix: o.IdentitySuffix,
  192. UnstableResp3: o.UnstableResp3,
  193. // Note: MaintNotificationsConfig not supported for FailoverOptions
  194. }
  195. }
  196. // Simple returns basic options created from the universal options.
  197. func (o *UniversalOptions) Simple() *Options {
  198. addr := "127.0.0.1:6379"
  199. if len(o.Addrs) > 0 {
  200. addr = o.Addrs[0]
  201. }
  202. return &Options{
  203. Addr: addr,
  204. ClientName: o.ClientName,
  205. Dialer: o.Dialer,
  206. OnConnect: o.OnConnect,
  207. DB: o.DB,
  208. Protocol: o.Protocol,
  209. Username: o.Username,
  210. Password: o.Password,
  211. CredentialsProvider: o.CredentialsProvider,
  212. CredentialsProviderContext: o.CredentialsProviderContext,
  213. StreamingCredentialsProvider: o.StreamingCredentialsProvider,
  214. MaxRetries: o.MaxRetries,
  215. MinRetryBackoff: o.MinRetryBackoff,
  216. MaxRetryBackoff: o.MaxRetryBackoff,
  217. DialTimeout: o.DialTimeout,
  218. ReadTimeout: o.ReadTimeout,
  219. WriteTimeout: o.WriteTimeout,
  220. ContextTimeoutEnabled: o.ContextTimeoutEnabled,
  221. ReadBufferSize: o.ReadBufferSize,
  222. WriteBufferSize: o.WriteBufferSize,
  223. PoolFIFO: o.PoolFIFO,
  224. PoolSize: o.PoolSize,
  225. PoolTimeout: o.PoolTimeout,
  226. MinIdleConns: o.MinIdleConns,
  227. MaxIdleConns: o.MaxIdleConns,
  228. MaxActiveConns: o.MaxActiveConns,
  229. ConnMaxIdleTime: o.ConnMaxIdleTime,
  230. ConnMaxLifetime: o.ConnMaxLifetime,
  231. TLSConfig: o.TLSConfig,
  232. DisableIdentity: o.DisableIdentity,
  233. DisableIndentity: o.DisableIndentity,
  234. IdentitySuffix: o.IdentitySuffix,
  235. UnstableResp3: o.UnstableResp3,
  236. MaintNotificationsConfig: o.MaintNotificationsConfig,
  237. }
  238. }
  239. // --------------------------------------------------------------------
  240. // UniversalClient is an abstract client which - based on the provided options -
  241. // represents either a ClusterClient, a FailoverClient, or a single-node Client.
  242. // This can be useful for testing cluster-specific applications locally or having different
  243. // clients in different environments.
  244. type UniversalClient interface {
  245. Cmdable
  246. AddHook(Hook)
  247. Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
  248. Do(ctx context.Context, args ...interface{}) *Cmd
  249. Process(ctx context.Context, cmd Cmder) error
  250. Subscribe(ctx context.Context, channels ...string) *PubSub
  251. PSubscribe(ctx context.Context, channels ...string) *PubSub
  252. SSubscribe(ctx context.Context, channels ...string) *PubSub
  253. Close() error
  254. PoolStats() *PoolStats
  255. }
  256. var (
  257. _ UniversalClient = (*Client)(nil)
  258. _ UniversalClient = (*ClusterClient)(nil)
  259. _ UniversalClient = (*Ring)(nil)
  260. )
  261. // NewUniversalClient returns a new multi client. The type of the returned client depends
  262. // on the following conditions:
  263. //
  264. // 1. If the MasterName option is specified with RouteByLatency, RouteRandomly or IsClusterMode,
  265. // a FailoverClusterClient is returned.
  266. // 2. If the MasterName option is specified without RouteByLatency, RouteRandomly or IsClusterMode,
  267. // a sentinel-backed FailoverClient is returned.
  268. // 3. If the number of Addrs is two or more, or IsClusterMode option is specified,
  269. // a ClusterClient is returned.
  270. // 4. Otherwise, a single-node Client is returned.
  271. func NewUniversalClient(opts *UniversalOptions) UniversalClient {
  272. if opts == nil {
  273. panic("redis: NewUniversalClient nil options")
  274. }
  275. switch {
  276. case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly || opts.IsClusterMode):
  277. return NewFailoverClusterClient(opts.Failover())
  278. case opts.MasterName != "":
  279. return NewFailoverClient(opts.Failover())
  280. case len(opts.Addrs) > 1 || opts.IsClusterMode:
  281. return NewClusterClient(opts.Cluster())
  282. default:
  283. return NewClient(opts.Simple())
  284. }
  285. }