example_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. package redis_test
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "github.com/go-redis/redis/v7"
  8. )
  9. var rdb *redis.Client
  10. func init() {
  11. rdb = redis.NewClient(&redis.Options{
  12. Addr: ":6379",
  13. DialTimeout: 10 * time.Second,
  14. ReadTimeout: 30 * time.Second,
  15. WriteTimeout: 30 * time.Second,
  16. PoolSize: 10,
  17. PoolTimeout: 30 * time.Second,
  18. })
  19. }
  20. func ExampleNewClient() {
  21. rdb := redis.NewClient(&redis.Options{
  22. Addr: "localhost:6379", // use default Addr
  23. Password: "", // no password set
  24. DB: 0, // use default DB
  25. })
  26. pong, err := rdb.Ping().Result()
  27. fmt.Println(pong, err)
  28. // Output: PONG <nil>
  29. }
  30. func ExampleParseURL() {
  31. opt, err := redis.ParseURL("redis://:qwerty@localhost:6379/1")
  32. if err != nil {
  33. panic(err)
  34. }
  35. fmt.Println("addr is", opt.Addr)
  36. fmt.Println("db is", opt.DB)
  37. fmt.Println("password is", opt.Password)
  38. // Create client as usually.
  39. _ = redis.NewClient(opt)
  40. // Output: addr is localhost:6379
  41. // db is 1
  42. // password is qwerty
  43. }
  44. func ExampleNewFailoverClient() {
  45. // See http://redis.io/topics/sentinel for instructions how to
  46. // setup Redis Sentinel.
  47. rdb := redis.NewFailoverClient(&redis.FailoverOptions{
  48. MasterName: "master",
  49. SentinelAddrs: []string{":26379"},
  50. })
  51. rdb.Ping()
  52. }
  53. func ExampleNewClusterClient() {
  54. // See http://redis.io/topics/cluster-tutorial for instructions
  55. // how to setup Redis Cluster.
  56. rdb := redis.NewClusterClient(&redis.ClusterOptions{
  57. Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
  58. })
  59. rdb.Ping()
  60. }
  61. // Following example creates a cluster from 2 master nodes and 2 slave nodes
  62. // without using cluster mode or Redis Sentinel.
  63. func ExampleNewClusterClient_manualSetup() {
  64. // clusterSlots returns cluster slots information.
  65. // It can use service like ZooKeeper to maintain configuration information
  66. // and Cluster.ReloadState to manually trigger state reloading.
  67. clusterSlots := func() ([]redis.ClusterSlot, error) {
  68. slots := []redis.ClusterSlot{
  69. // First node with 1 master and 1 slave.
  70. {
  71. Start: 0,
  72. End: 8191,
  73. Nodes: []redis.ClusterNode{{
  74. Addr: ":7000", // master
  75. }, {
  76. Addr: ":8000", // 1st slave
  77. }},
  78. },
  79. // Second node with 1 master and 1 slave.
  80. {
  81. Start: 8192,
  82. End: 16383,
  83. Nodes: []redis.ClusterNode{{
  84. Addr: ":7001", // master
  85. }, {
  86. Addr: ":8001", // 1st slave
  87. }},
  88. },
  89. }
  90. return slots, nil
  91. }
  92. rdb := redis.NewClusterClient(&redis.ClusterOptions{
  93. ClusterSlots: clusterSlots,
  94. RouteRandomly: true,
  95. })
  96. rdb.Ping()
  97. // ReloadState reloads cluster state. It calls ClusterSlots func
  98. // to get cluster slots information.
  99. err := rdb.ReloadState()
  100. if err != nil {
  101. panic(err)
  102. }
  103. }
  104. func ExampleNewRing() {
  105. rdb := redis.NewRing(&redis.RingOptions{
  106. Addrs: map[string]string{
  107. "shard1": ":7000",
  108. "shard2": ":7001",
  109. "shard3": ":7002",
  110. },
  111. })
  112. rdb.Ping()
  113. }
  114. func ExampleClient() {
  115. err := rdb.Set("key", "value", 0).Err()
  116. if err != nil {
  117. panic(err)
  118. }
  119. val, err := rdb.Get("key").Result()
  120. if err != nil {
  121. panic(err)
  122. }
  123. fmt.Println("key", val)
  124. val2, err := rdb.Get("missing_key").Result()
  125. if err == redis.Nil {
  126. fmt.Println("missing_key does not exist")
  127. } else if err != nil {
  128. panic(err)
  129. } else {
  130. fmt.Println("missing_key", val2)
  131. }
  132. // Output: key value
  133. // missing_key does not exist
  134. }
  135. func ExampleConn() {
  136. conn := rdb.Conn()
  137. err := conn.ClientSetName("foobar").Err()
  138. if err != nil {
  139. panic(err)
  140. }
  141. // Open other connections.
  142. for i := 0; i < 10; i++ {
  143. go rdb.Ping()
  144. }
  145. s, err := conn.ClientGetName().Result()
  146. if err != nil {
  147. panic(err)
  148. }
  149. fmt.Println(s)
  150. // Output: foobar
  151. }
  152. func ExampleClient_Set() {
  153. // Last argument is expiration. Zero means the key has no
  154. // expiration time.
  155. err := rdb.Set("key", "value", 0).Err()
  156. if err != nil {
  157. panic(err)
  158. }
  159. // key2 will expire in an hour.
  160. err = rdb.Set("key2", "value", time.Hour).Err()
  161. if err != nil {
  162. panic(err)
  163. }
  164. }
  165. func ExampleClient_Incr() {
  166. result, err := rdb.Incr("counter").Result()
  167. if err != nil {
  168. panic(err)
  169. }
  170. fmt.Println(result)
  171. // Output: 1
  172. }
  173. func ExampleClient_BLPop() {
  174. if err := rdb.RPush("queue", "message").Err(); err != nil {
  175. panic(err)
  176. }
  177. // use `rdb.BLPop(0, "queue")` for infinite waiting time
  178. result, err := rdb.BLPop(1*time.Second, "queue").Result()
  179. if err != nil {
  180. panic(err)
  181. }
  182. fmt.Println(result[0], result[1])
  183. // Output: queue message
  184. }
  185. func ExampleClient_Scan() {
  186. rdb.FlushDB()
  187. for i := 0; i < 33; i++ {
  188. err := rdb.Set(fmt.Sprintf("key%d", i), "value", 0).Err()
  189. if err != nil {
  190. panic(err)
  191. }
  192. }
  193. var cursor uint64
  194. var n int
  195. for {
  196. var keys []string
  197. var err error
  198. keys, cursor, err = rdb.Scan(cursor, "key*", 10).Result()
  199. if err != nil {
  200. panic(err)
  201. }
  202. n += len(keys)
  203. if cursor == 0 {
  204. break
  205. }
  206. }
  207. fmt.Printf("found %d keys\n", n)
  208. // Output: found 33 keys
  209. }
  210. func ExampleClient_Pipelined() {
  211. var incr *redis.IntCmd
  212. _, err := rdb.Pipelined(func(pipe redis.Pipeliner) error {
  213. incr = pipe.Incr("pipelined_counter")
  214. pipe.Expire("pipelined_counter", time.Hour)
  215. return nil
  216. })
  217. fmt.Println(incr.Val(), err)
  218. // Output: 1 <nil>
  219. }
  220. func ExampleClient_Pipeline() {
  221. pipe := rdb.Pipeline()
  222. incr := pipe.Incr("pipeline_counter")
  223. pipe.Expire("pipeline_counter", time.Hour)
  224. // Execute
  225. //
  226. // INCR pipeline_counter
  227. // EXPIRE pipeline_counts 3600
  228. //
  229. // using one rdb-server roundtrip.
  230. _, err := pipe.Exec()
  231. fmt.Println(incr.Val(), err)
  232. // Output: 1 <nil>
  233. }
  234. func ExampleClient_TxPipelined() {
  235. var incr *redis.IntCmd
  236. _, err := rdb.TxPipelined(func(pipe redis.Pipeliner) error {
  237. incr = pipe.Incr("tx_pipelined_counter")
  238. pipe.Expire("tx_pipelined_counter", time.Hour)
  239. return nil
  240. })
  241. fmt.Println(incr.Val(), err)
  242. // Output: 1 <nil>
  243. }
  244. func ExampleClient_TxPipeline() {
  245. pipe := rdb.TxPipeline()
  246. incr := pipe.Incr("tx_pipeline_counter")
  247. pipe.Expire("tx_pipeline_counter", time.Hour)
  248. // Execute
  249. //
  250. // MULTI
  251. // INCR pipeline_counter
  252. // EXPIRE pipeline_counts 3600
  253. // EXEC
  254. //
  255. // using one rdb-server roundtrip.
  256. _, err := pipe.Exec()
  257. fmt.Println(incr.Val(), err)
  258. // Output: 1 <nil>
  259. }
  260. func ExampleClient_Watch() {
  261. const routineCount = 100
  262. // Transactionally increments key using GET and SET commands.
  263. increment := func(key string) error {
  264. txf := func(tx *redis.Tx) error {
  265. // get current value or zero
  266. n, err := tx.Get(key).Int()
  267. if err != nil && err != redis.Nil {
  268. return err
  269. }
  270. // actual opperation (local in optimistic lock)
  271. n++
  272. // runs only if the watched keys remain unchanged
  273. _, err = tx.TxPipelined(func(pipe redis.Pipeliner) error {
  274. // pipe handles the error case
  275. pipe.Set(key, n, 0)
  276. return nil
  277. })
  278. return err
  279. }
  280. for retries := routineCount; retries > 0; retries-- {
  281. err := rdb.Watch(txf, key)
  282. if err != redis.TxFailedErr {
  283. return err
  284. }
  285. // optimistic lock lost
  286. }
  287. return errors.New("increment reached maximum number of retries")
  288. }
  289. var wg sync.WaitGroup
  290. wg.Add(routineCount)
  291. for i := 0; i < routineCount; i++ {
  292. go func() {
  293. defer wg.Done()
  294. if err := increment("counter3"); err != nil {
  295. fmt.Println("increment error:", err)
  296. }
  297. }()
  298. }
  299. wg.Wait()
  300. n, err := rdb.Get("counter3").Int()
  301. fmt.Println("ended with", n, err)
  302. // Output: ended with 100 <nil>
  303. }
  304. func ExamplePubSub() {
  305. pubsub := rdb.Subscribe("mychannel1")
  306. // Wait for confirmation that subscription is created before publishing anything.
  307. _, err := pubsub.Receive()
  308. if err != nil {
  309. panic(err)
  310. }
  311. // Go channel which receives messages.
  312. ch := pubsub.Channel()
  313. // Publish a message.
  314. err = rdb.Publish("mychannel1", "hello").Err()
  315. if err != nil {
  316. panic(err)
  317. }
  318. time.AfterFunc(time.Second, func() {
  319. // When pubsub is closed channel is closed too.
  320. _ = pubsub.Close()
  321. })
  322. // Consume messages.
  323. for msg := range ch {
  324. fmt.Println(msg.Channel, msg.Payload)
  325. }
  326. // Output: mychannel1 hello
  327. }
  328. func ExamplePubSub_Receive() {
  329. pubsub := rdb.Subscribe("mychannel2")
  330. defer pubsub.Close()
  331. for i := 0; i < 2; i++ {
  332. // ReceiveTimeout is a low level API. Use ReceiveMessage instead.
  333. msgi, err := pubsub.ReceiveTimeout(time.Second)
  334. if err != nil {
  335. break
  336. }
  337. switch msg := msgi.(type) {
  338. case *redis.Subscription:
  339. fmt.Println("subscribed to", msg.Channel)
  340. _, err := rdb.Publish("mychannel2", "hello").Result()
  341. if err != nil {
  342. panic(err)
  343. }
  344. case *redis.Message:
  345. fmt.Println("received", msg.Payload, "from", msg.Channel)
  346. default:
  347. panic("unreached")
  348. }
  349. }
  350. // sent message to 1 rdb
  351. // received hello from mychannel2
  352. }
  353. func ExampleScript() {
  354. IncrByXX := redis.NewScript(`
  355. if redis.call("GET", KEYS[1]) ~= false then
  356. return redis.call("INCRBY", KEYS[1], ARGV[1])
  357. end
  358. return false
  359. `)
  360. n, err := IncrByXX.Run(rdb, []string{"xx_counter"}, 2).Result()
  361. fmt.Println(n, err)
  362. err = rdb.Set("xx_counter", "40", 0).Err()
  363. if err != nil {
  364. panic(err)
  365. }
  366. n, err = IncrByXX.Run(rdb, []string{"xx_counter"}, 2).Result()
  367. fmt.Println(n, err)
  368. // Output: <nil> redis: nil
  369. // 42 <nil>
  370. }
  371. func Example_customCommand() {
  372. Get := func(rdb *redis.Client, key string) *redis.StringCmd {
  373. cmd := redis.NewStringCmd("get", key)
  374. rdb.Process(cmd)
  375. return cmd
  376. }
  377. v, err := Get(rdb, "key_does_not_exist").Result()
  378. fmt.Printf("%q %s", v, err)
  379. // Output: "" redis: nil
  380. }
  381. func Example_customCommand2() {
  382. v, err := rdb.Do("get", "key_does_not_exist").String()
  383. fmt.Printf("%q %s", v, err)
  384. // Output: "" redis: nil
  385. }
  386. func ExampleScanIterator() {
  387. iter := rdb.Scan(0, "", 0).Iterator()
  388. for iter.Next() {
  389. fmt.Println(iter.Val())
  390. }
  391. if err := iter.Err(); err != nil {
  392. panic(err)
  393. }
  394. }
  395. func ExampleScanCmd_Iterator() {
  396. iter := rdb.Scan(0, "", 0).Iterator()
  397. for iter.Next() {
  398. fmt.Println(iter.Val())
  399. }
  400. if err := iter.Err(); err != nil {
  401. panic(err)
  402. }
  403. }
  404. func ExampleNewUniversalClient_simple() {
  405. rdb := redis.NewUniversalClient(&redis.UniversalOptions{
  406. Addrs: []string{":6379"},
  407. })
  408. defer rdb.Close()
  409. rdb.Ping()
  410. }
  411. func ExampleNewUniversalClient_failover() {
  412. rdb := redis.NewUniversalClient(&redis.UniversalOptions{
  413. MasterName: "master",
  414. Addrs: []string{":26379"},
  415. })
  416. defer rdb.Close()
  417. rdb.Ping()
  418. }
  419. func ExampleNewUniversalClient_cluster() {
  420. rdb := redis.NewUniversalClient(&redis.UniversalOptions{
  421. Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
  422. })
  423. defer rdb.Close()
  424. rdb.Ping()
  425. }