universal.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package redis
  2. import (
  3. "crypto/tls"
  4. "time"
  5. )
  6. // UniversalOptions information is required by UniversalClient to establish
  7. // connections.
  8. type UniversalOptions struct {
  9. // Either a single address or a seed list of host:port addresses
  10. // of cluster/sentinel nodes.
  11. Addrs []string
  12. // Database to be selected after connecting to the server.
  13. // Only single-node and failover clients.
  14. DB int
  15. // Common options.
  16. OnConnect func(*Conn) error
  17. Password string
  18. MaxRetries int
  19. MinRetryBackoff time.Duration
  20. MaxRetryBackoff time.Duration
  21. DialTimeout time.Duration
  22. ReadTimeout time.Duration
  23. WriteTimeout time.Duration
  24. PoolSize int
  25. MinIdleConns int
  26. MaxConnAge time.Duration
  27. PoolTimeout time.Duration
  28. IdleTimeout time.Duration
  29. IdleCheckFrequency time.Duration
  30. TLSConfig *tls.Config
  31. // Only cluster clients.
  32. MaxRedirects int
  33. ReadOnly bool
  34. RouteByLatency bool
  35. RouteRandomly bool
  36. // The sentinel master name.
  37. // Only failover clients.
  38. MasterName string
  39. }
  40. func (o *UniversalOptions) cluster() *ClusterOptions {
  41. if len(o.Addrs) == 0 {
  42. o.Addrs = []string{"127.0.0.1:6379"}
  43. }
  44. return &ClusterOptions{
  45. Addrs: o.Addrs,
  46. OnConnect: o.OnConnect,
  47. Password: o.Password,
  48. MaxRedirects: o.MaxRedirects,
  49. ReadOnly: o.ReadOnly,
  50. RouteByLatency: o.RouteByLatency,
  51. RouteRandomly: o.RouteRandomly,
  52. MaxRetries: o.MaxRetries,
  53. MinRetryBackoff: o.MinRetryBackoff,
  54. MaxRetryBackoff: o.MaxRetryBackoff,
  55. DialTimeout: o.DialTimeout,
  56. ReadTimeout: o.ReadTimeout,
  57. WriteTimeout: o.WriteTimeout,
  58. PoolSize: o.PoolSize,
  59. MinIdleConns: o.MinIdleConns,
  60. MaxConnAge: o.MaxConnAge,
  61. PoolTimeout: o.PoolTimeout,
  62. IdleTimeout: o.IdleTimeout,
  63. IdleCheckFrequency: o.IdleCheckFrequency,
  64. TLSConfig: o.TLSConfig,
  65. }
  66. }
  67. func (o *UniversalOptions) failover() *FailoverOptions {
  68. if len(o.Addrs) == 0 {
  69. o.Addrs = []string{"127.0.0.1:26379"}
  70. }
  71. return &FailoverOptions{
  72. SentinelAddrs: o.Addrs,
  73. MasterName: o.MasterName,
  74. OnConnect: o.OnConnect,
  75. DB: o.DB,
  76. Password: o.Password,
  77. MaxRetries: o.MaxRetries,
  78. MinRetryBackoff: o.MinRetryBackoff,
  79. MaxRetryBackoff: o.MaxRetryBackoff,
  80. DialTimeout: o.DialTimeout,
  81. ReadTimeout: o.ReadTimeout,
  82. WriteTimeout: o.WriteTimeout,
  83. PoolSize: o.PoolSize,
  84. MinIdleConns: o.MinIdleConns,
  85. MaxConnAge: o.MaxConnAge,
  86. PoolTimeout: o.PoolTimeout,
  87. IdleTimeout: o.IdleTimeout,
  88. IdleCheckFrequency: o.IdleCheckFrequency,
  89. TLSConfig: o.TLSConfig,
  90. }
  91. }
  92. func (o *UniversalOptions) simple() *Options {
  93. addr := "127.0.0.1:6379"
  94. if len(o.Addrs) > 0 {
  95. addr = o.Addrs[0]
  96. }
  97. return &Options{
  98. Addr: addr,
  99. OnConnect: o.OnConnect,
  100. DB: o.DB,
  101. Password: o.Password,
  102. MaxRetries: o.MaxRetries,
  103. MinRetryBackoff: o.MinRetryBackoff,
  104. MaxRetryBackoff: o.MaxRetryBackoff,
  105. DialTimeout: o.DialTimeout,
  106. ReadTimeout: o.ReadTimeout,
  107. WriteTimeout: o.WriteTimeout,
  108. PoolSize: o.PoolSize,
  109. MinIdleConns: o.MinIdleConns,
  110. MaxConnAge: o.MaxConnAge,
  111. PoolTimeout: o.PoolTimeout,
  112. IdleTimeout: o.IdleTimeout,
  113. IdleCheckFrequency: o.IdleCheckFrequency,
  114. TLSConfig: o.TLSConfig,
  115. }
  116. }
  117. // --------------------------------------------------------------------
  118. // UniversalClient is an abstract client which - based on the provided options -
  119. // can connect to either clusters, or sentinel-backed failover instances or simple
  120. // single-instance servers. This can be useful for testing cluster-specific
  121. // applications locally.
  122. type UniversalClient interface {
  123. Cmdable
  124. Watch(fn func(*Tx) error, keys ...string) error
  125. Process(cmd Cmder) error
  126. WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error)
  127. Subscribe(channels ...string) *PubSub
  128. PSubscribe(channels ...string) *PubSub
  129. Close() error
  130. }
  131. var _ UniversalClient = (*Client)(nil)
  132. var _ UniversalClient = (*ClusterClient)(nil)
  133. // NewUniversalClient returns a new multi client. The type of client returned depends
  134. // on the following three conditions:
  135. //
  136. // 1. if a MasterName is passed a sentinel-backed FailoverClient will be returned
  137. // 2. if the number of Addrs is two or more, a ClusterClient will be returned
  138. // 3. otherwise, a single-node redis Client will be returned.
  139. func NewUniversalClient(opts *UniversalOptions) UniversalClient {
  140. if opts.MasterName != "" {
  141. return NewFailoverClient(opts.failover())
  142. } else if len(opts.Addrs) > 1 {
  143. return NewClusterClient(opts.cluster())
  144. }
  145. return NewClient(opts.simple())
  146. }