14 "github.com/go-redis/redis/internal/pool"
17 // Limiter is the interface of a rate limiter or a circuit breaker.
18 type Limiter interface {
19 // Allow returns a nil if operation is allowed or an error otherwise.
20 // If operation is allowed client must report the result of operation
21 // whether is a success or a failure.
23 // ReportResult reports the result of previously allowed operation.
24 // nil indicates a success, non-nil error indicates a failure.
25 ReportResult(result error)
29 // The network type, either tcp or unix.
35 // Dialer creates new network connection and has priority over
36 // Network and Addr options.
37 Dialer func() (net.Conn, error)
39 // Hook that is called when new connection is established.
40 OnConnect func(*Conn) error
42 // Optional password. Must match the password specified in the
43 // requirepass server configuration option.
45 // Database to be selected after connecting to the server.
48 // Maximum number of retries before giving up.
49 // Default is to not retry failed commands.
51 // Minimum backoff between each retry.
52 // Default is 8 milliseconds; -1 disables backoff.
53 MinRetryBackoff time.Duration
54 // Maximum backoff between each retry.
55 // Default is 512 milliseconds; -1 disables backoff.
56 MaxRetryBackoff time.Duration
58 // Dial timeout for establishing new connections.
59 // Default is 5 seconds.
60 DialTimeout time.Duration
61 // Timeout for socket reads. If reached, commands will fail
62 // with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
63 // Default is 3 seconds.
64 ReadTimeout time.Duration
65 // Timeout for socket writes. If reached, commands will fail
66 // with a timeout instead of blocking.
67 // Default is ReadTimeout.
68 WriteTimeout time.Duration
70 // Maximum number of socket connections.
71 // Default is 10 connections per every CPU as reported by runtime.NumCPU.
73 // Minimum number of idle connections which is useful when establishing
74 // new connection is slow.
76 // Connection age at which client retires (closes) the connection.
77 // Default is to not close aged connections.
78 MaxConnAge time.Duration
79 // Amount of time client waits for connection if all connections
80 // are busy before returning an error.
81 // Default is ReadTimeout + 1 second.
82 PoolTimeout time.Duration
83 // Amount of time after which client closes idle connections.
84 // Should be less than server's timeout.
85 // Default is 5 minutes. -1 disables idle timeout check.
86 IdleTimeout time.Duration
87 // Frequency of idle checks made by idle connections reaper.
88 // Default is 1 minute. -1 disables idle connections reaper,
89 // but idle connections are still discarded by the client
90 // if IdleTimeout is set.
91 IdleCheckFrequency time.Duration
93 // Enables read only queries on slave nodes.
96 // TLS Config to use. When set TLS will be negotiated.
100 func (opt *Options) init() {
101 if opt.Network == "" {
105 opt.Addr = "localhost:6379"
107 if opt.Dialer == nil {
108 opt.Dialer = func() (net.Conn, error) {
109 netDialer := &net.Dialer{
110 Timeout: opt.DialTimeout,
111 KeepAlive: 5 * time.Minute,
113 if opt.TLSConfig == nil {
114 return netDialer.Dial(opt.Network, opt.Addr)
116 return tls.DialWithDialer(netDialer, opt.Network, opt.Addr, opt.TLSConfig)
120 if opt.PoolSize == 0 {
121 opt.PoolSize = 10 * runtime.NumCPU()
123 if opt.DialTimeout == 0 {
124 opt.DialTimeout = 5 * time.Second
126 switch opt.ReadTimeout {
130 opt.ReadTimeout = 3 * time.Second
132 switch opt.WriteTimeout {
136 opt.WriteTimeout = opt.ReadTimeout
138 if opt.PoolTimeout == 0 {
139 opt.PoolTimeout = opt.ReadTimeout + time.Second
141 if opt.IdleTimeout == 0 {
142 opt.IdleTimeout = 5 * time.Minute
144 if opt.IdleCheckFrequency == 0 {
145 opt.IdleCheckFrequency = time.Minute
148 switch opt.MinRetryBackoff {
150 opt.MinRetryBackoff = 0
152 opt.MinRetryBackoff = 8 * time.Millisecond
154 switch opt.MaxRetryBackoff {
156 opt.MaxRetryBackoff = 0
158 opt.MaxRetryBackoff = 512 * time.Millisecond
162 // ParseURL parses an URL into Options that can be used to connect to Redis.
163 func ParseURL(redisURL string) (*Options, error) {
164 o := &Options{Network: "tcp"}
165 u, err := url.Parse(redisURL)
170 if u.Scheme != "redis" && u.Scheme != "rediss" {
171 return nil, errors.New("invalid redis URL scheme: " + u.Scheme)
175 if p, ok := u.User.Password(); ok {
180 if len(u.Query()) > 0 {
181 return nil, errors.New("no options supported")
184 h, p, err := net.SplitHostPort(u.Host)
194 o.Addr = net.JoinHostPort(h, p)
196 f := strings.FieldsFunc(u.Path, func(r rune) bool {
203 if o.DB, err = strconv.Atoi(f[0]); err != nil {
204 return nil, fmt.Errorf("invalid redis database number: %q", f[0])
207 return nil, errors.New("invalid redis URL path: " + u.Path)
210 if u.Scheme == "rediss" {
211 o.TLSConfig = &tls.Config{ServerName: h}
216 func newConnPool(opt *Options) *pool.ConnPool {
217 return pool.NewConnPool(&pool.Options{
219 PoolSize: opt.PoolSize,
220 MinIdleConns: opt.MinIdleConns,
221 MaxConnAge: opt.MaxConnAge,
222 PoolTimeout: opt.PoolTimeout,
223 IdleTimeout: opt.IdleTimeout,
224 IdleCheckFrequency: opt.IdleCheckFrequency,