radix.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Package radix implements all functionality needed to work with redis and all
  2. // things related to it, including redis cluster, pubsub, sentinel, scanning,
  3. // lua scripting, and more.
  4. //
  5. // Creating a client
  6. //
  7. // For a single node redis instance use NewPool to create a connection pool. The
  8. // connection pool is thread-safe and will automatically create, reuse, and
  9. // recreate connections as needed:
  10. //
  11. // pool, err := radix.NewPool("tcp", "127.0.0.1:6379", 10)
  12. // if err != nil {
  13. // // handle error
  14. // }
  15. //
  16. // If you're using sentinel or cluster you should use NewSentinel or NewCluster
  17. // (respectively) to create your client instead.
  18. //
  19. // Commands
  20. //
  21. // Any redis command can be performed by passing a Cmd into a Client's Do
  22. // method. Each Cmd should only be used once. The return from the Cmd can be
  23. // captured into any appopriate go primitive type, or a slice, map, or struct,
  24. // if the command returns an array.
  25. //
  26. // err := client.Do(radix.Cmd(nil, "SET", "foo", "someval"))
  27. //
  28. // var fooVal string
  29. // err := client.Do(radix.Cmd(&fooVal, "GET", "foo"))
  30. //
  31. // var fooValB []byte
  32. // err := client.Do(radix.Cmd(&fooValB, "GET", "foo"))
  33. //
  34. // var barI int
  35. // err := client.Do(radix.Cmd(&barI, "INCR", "bar"))
  36. //
  37. // var bazEls []string
  38. // err := client.Do(radix.Cmd(&bazEls, "LRANGE", "baz", "0", "-1"))
  39. //
  40. // var buzMap map[string]string
  41. // err := client.Do(radix.Cmd(&buzMap, "HGETALL", "buz"))
  42. //
  43. // FlatCmd can also be used if you wish to use non-string arguments like
  44. // integers, slices, maps, or structs, and have them automatically be flattened
  45. // into a single string slice.
  46. //
  47. // Struct Scanning
  48. //
  49. // Cmd and FlatCmd can unmarshal results into a struct. The results must be a
  50. // key/value array, such as that returned by HGETALL. Exported field names will
  51. // be used as keys, unless the fields have the "redis" tag:
  52. //
  53. // type MyType struct {
  54. // Foo string // Will be populated with the value for key "Foo"
  55. // Bar string `redis:"BAR"` // Will be populated with the value for key "BAR"
  56. // Baz string `redis:"-"` // Will not be populated
  57. // }
  58. //
  59. // Embedded structs will inline that struct's fields into the parent's:
  60. //
  61. // type MyOtherType struct {
  62. // // adds fields "Foo" and "BAR" (from above example) to MyOtherType
  63. // MyType
  64. // Biz int
  65. // }
  66. //
  67. // The same rules for field naming apply when a struct is passed into FlatCmd as
  68. // an argument.
  69. //
  70. // Actions
  71. //
  72. // Cmd and FlatCmd both implement the Action interface. Other Actions include
  73. // Pipeline, WithConn, and EvalScript.Cmd. Any of these may be passed into any
  74. // Client's Do method.
  75. //
  76. // var fooVal string
  77. // p := radix.Pipeline(
  78. // radix.FlatCmd(nil, "SET", "foo", 1),
  79. // radix.Cmd(&fooVal, "GET", "foo"),
  80. // )
  81. // if err := client.Do(p); err != nil {
  82. // panic(err)
  83. // }
  84. // fmt.Printf("fooVal: %q\n", fooVal)
  85. //
  86. // Transactions
  87. //
  88. // There are two ways to perform transactions in redis. The first is with the
  89. // MULTI/EXEC commands, which can be done using the WithConn Action (see its
  90. // example). The second is using EVAL with lua scripting, which can be done
  91. // using the EvalScript Action (again, see its example).
  92. //
  93. // EVAL with lua scripting is recommended in almost all cases. It only requires
  94. // a single round-trip, it's infinitely more flexible than MULTI/EXEC, it's
  95. // simpler to code, and for complex transactions, which would otherwise need a
  96. // WATCH statement with MULTI/EXEC, it's significantly faster.
  97. //
  98. // AUTH and other settings via ConnFunc and ClientFunc
  99. //
  100. // All the client creation functions (e.g. NewPool) take in either a ConnFunc or
  101. // a ClientFunc via their options. These can be used in order to set up timeouts
  102. // on connections, perform authentication commands, or even implement custom
  103. // pools.
  104. //
  105. // // this is a ConnFunc which will set up a connection which is authenticated
  106. // // and has a 1 minute timeout on all operations
  107. // customConnFunc := func(network, addr string) (radix.Conn, error) {
  108. // return radix.Dial(network, addr,
  109. // radix.DialTimeout(1 * time.Minute),
  110. // radix.DialAuthPass("mySuperSecretPassword"),
  111. // )
  112. // }
  113. //
  114. // // this pool will use our ConnFunc for all connections it creates
  115. // pool, err := radix.NewPool("tcp", redisAddr, 10, PoolConnFunc(customConnFunc))
  116. //
  117. // // this cluster will use the ClientFunc to create a pool to each node in the
  118. // // cluster. The pools also use our customConnFunc, but have more connections
  119. // poolFunc := func(network, addr string) (radix.Client, error) {
  120. // return radix.NewPool(network, addr, 100, PoolConnFunc(customConnFunc))
  121. // }
  122. // cluster, err := radix.NewCluster([]string{redisAddr1, redisAddr2}, ClusterPoolFunc(poolFunc))
  123. //
  124. // Custom implementations
  125. //
  126. // All interfaces in this package were designed such that they could have custom
  127. // implementations. There is no dependency within radix that demands any
  128. // interface be implemented by a particular underlying type, so feel free to
  129. // create your own Pools or Conns or Actions or whatever makes your life easier.
  130. //
  131. // Errors
  132. //
  133. // Errors returned from redis can be explicitly checked for using the the
  134. // resp2.Error type. Note that the errors.As function, introduced in go 1.13,
  135. // should be used.
  136. //
  137. // var redisErr resp2.Error
  138. // err := client.Do(radix.Cmd(nil, "AUTH", "wrong password"))
  139. // if errors.As(err, &redisErr) {
  140. // log.Printf("redis error returned: %s", redisErr.E)
  141. // }
  142. //
  143. // Use the golang.org/x/xerrors package if you're using an older version of go.
  144. //
  145. // Implicit pipelining
  146. //
  147. // Implicit pipelining is an optimization implemented and enabled in the default
  148. // Pool implementation (and therefore also used by Cluster and Sentinel) which
  149. // involves delaying concurrent Cmds and FlatCmds a small amount of time and
  150. // sending them to redis in a single batch, similar to manually using a Pipeline.
  151. // By doing this radix significantly reduces the I/O and CPU overhead for
  152. // concurrent requests.
  153. //
  154. // Note that only commands which do not block are eligible for implicit pipelining.
  155. //
  156. // See the documentation on Pool for more information about the current
  157. // implementation of implicit pipelining and for how to configure or disable
  158. // the feature.
  159. //
  160. // For a performance comparisons between Clients with and without implicit
  161. // pipelining see the benchmark results in the README.md.
  162. //
  163. package radix
  164. import (
  165. "errors"
  166. )
  167. var errClientClosed = errors.New("client is closed")
  168. // Client describes an entity which can carry out Actions, e.g. a connection
  169. // pool for a single redis instance or the cluster client.
  170. //
  171. // Implementations of Client are expected to be thread-safe, except in cases
  172. // like Conn where they specify otherwise.
  173. type Client interface {
  174. // Do performs an Action, returning any error.
  175. Do(Action) error
  176. // Once Close() is called all future method calls on the Client will return
  177. // an error
  178. Close() error
  179. }
  180. // ClientFunc is a function which can be used to create a Client for a single
  181. // redis instance on the given network/address.
  182. type ClientFunc func(network, addr string) (Client, error)
  183. // DefaultClientFunc is a ClientFunc which will return a Client for a redis
  184. // instance using sane defaults.
  185. var DefaultClientFunc = func(network, addr string) (Client, error) {
  186. return NewPool(network, addr, 4)
  187. }